@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
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# sync-wallet-fixture.sh — copy the wallet fixture to the canonical runtime slot.
|
|
3
|
+
#
|
|
4
|
+
# Purpose:
|
|
5
|
+
# After a successful overlay install, ensures the canonical wallet fixture is
|
|
6
|
+
# present in the checkout's runtime dir. Non-zero exit is informational (no
|
|
7
|
+
# fixture source found); the install already succeeded, so the overlay is fresh.
|
|
8
|
+
#
|
|
9
|
+
# Inputs (flags / env):
|
|
10
|
+
# --target <checkout> (default $PWD)
|
|
11
|
+
# --slot-id <id> (env FARMSLOT_SLOT_ID, SLOT_ID — farmslot sync source)
|
|
12
|
+
# --cdp-port <port> (env CDP_PORT — extension fixture seeding port)
|
|
13
|
+
#
|
|
14
|
+
# Outputs:
|
|
15
|
+
# Copies wallet-fixture.json to <target>/<RECIPE_RUNTIME_DIR>/wallet-fixture.json
|
|
16
|
+
# when a source is found. Exit 0 always (non-zero only when no source found;
|
|
17
|
+
# callers treat this as informational).
|
|
18
|
+
#
|
|
19
|
+
# OS-glue only: file copy and farmslot delegation; decision logic lives in
|
|
20
|
+
# src/commands/fixtures.ts.
|
|
21
|
+
set -uo pipefail
|
|
22
|
+
|
|
23
|
+
TARGET="$PWD"
|
|
24
|
+
SLOT_ID="${FARMSLOT_SLOT_ID:-${SLOT_ID:-}}"
|
|
25
|
+
CDP_PORT="${CDP_PORT:-}"
|
|
26
|
+
|
|
27
|
+
require_value() { [ "$#" -ge 2 ] || { printf 'Missing value for %s\n' "$1" >&2; exit 2; }; }
|
|
28
|
+
|
|
29
|
+
while [ "$#" -gt 0 ]; do
|
|
30
|
+
case "$1" in
|
|
31
|
+
--target) require_value "$@"; TARGET="$2"; shift 2 ;;
|
|
32
|
+
--slot-id) require_value "$@"; SLOT_ID="$2"; shift 2 ;;
|
|
33
|
+
--cdp-port) require_value "$@"; CDP_PORT="$2"; shift 2 ;;
|
|
34
|
+
-h|--help)
|
|
35
|
+
printf 'Usage: sync-wallet-fixture.sh [--target <dir>] [--slot-id <id>] [--cdp-port <port>]\n'
|
|
36
|
+
exit 0
|
|
37
|
+
;;
|
|
38
|
+
*) printf 'Unknown arg: %s\n' "$1" >&2; exit 2 ;;
|
|
39
|
+
esac
|
|
40
|
+
done
|
|
41
|
+
|
|
42
|
+
TARGET="$(cd "$TARGET" && pwd)"
|
|
43
|
+
RUNTIME_DIR="${RECIPE_RUNTIME_DIR:-temp/recipe/runtime}"
|
|
44
|
+
CANONICAL="$TARGET/$RUNTIME_DIR/wallet-fixture.json"
|
|
45
|
+
|
|
46
|
+
mkdir -p "$(dirname "$CANONICAL")"
|
|
47
|
+
|
|
48
|
+
# Already present — nothing to do.
|
|
49
|
+
if [ -f "$CANONICAL" ]; then
|
|
50
|
+
exit 0
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# RECIPE_WALLET_FIXTURE env points at a fixture directly.
|
|
54
|
+
if [ -n "${RECIPE_WALLET_FIXTURE:-}" ] && [ -f "${RECIPE_WALLET_FIXTURE}" ]; then
|
|
55
|
+
cp "${RECIPE_WALLET_FIXTURE}" "$CANONICAL"
|
|
56
|
+
chmod 600 "$CANONICAL" 2>/dev/null || true
|
|
57
|
+
printf 'sync-wallet-fixture: linked wallet-fixture.json from RECIPE_WALLET_FIXTURE\n' >&2
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Farmslot slot sync (requires farmslot root and sync-fixtures.sh).
|
|
62
|
+
if [ -n "$SLOT_ID" ]; then
|
|
63
|
+
FARMSLOT_ROOT="${FARMSLOT_ROOT:-}"
|
|
64
|
+
for candidate in "$HOME/dev/farmslot" "$HOME/farmslot"; do
|
|
65
|
+
[ -d "$candidate/scripts" ] || continue
|
|
66
|
+
FARMSLOT_ROOT="$candidate"
|
|
67
|
+
break
|
|
68
|
+
done
|
|
69
|
+
if [ -n "$FARMSLOT_ROOT" ] && [ -f "$FARMSLOT_ROOT/scripts/sync-fixtures.sh" ]; then
|
|
70
|
+
if bash "$FARMSLOT_ROOT/scripts/sync-fixtures.sh" --slot "$SLOT_ID" 2>/dev/null; then
|
|
71
|
+
[ -f "$CANONICAL" ] && exit 0
|
|
72
|
+
fi
|
|
73
|
+
fi
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# No fixture source found — informational non-zero (callers tolerate this).
|
|
77
|
+
printf 'sync-wallet-fixture: no wallet fixture source found for %s\n' "$TARGET" >&2
|
|
78
|
+
exit 1
|
package/bin/mm-harness
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# mm-harness — the single front door for the MetaMask recipe loop.
|
|
3
3
|
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# manifest/live/runtime-*) stay reachable via their own bins until the caller sweep.
|
|
4
|
+
# The entry is the commander-based CLI (src/mm-harness-cli.ts) that presents the
|
|
5
|
+
# end-state surface; it resolves node/tsx/dist the same way whether the package is
|
|
6
|
+
# installed as a dependency or run from a source checkout.
|
|
8
7
|
set -euo pipefail
|
|
9
8
|
SOURCE="${BASH_SOURCE[0]}"
|
|
10
9
|
while [ -L "$SOURCE" ]; do
|
|
@@ -19,13 +18,45 @@ done
|
|
|
19
18
|
SCRIPT_DIR="$(cd "$(dirname "$SOURCE")" && pwd -P)"
|
|
20
19
|
RUNNER_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
# Dev/prod switch (the single override point). MM_HARNESS_BIN, when set, is the
|
|
22
|
+
# authoritative path to a dev checkout's bin/mm-harness with active pre-release
|
|
23
|
+
# changes; unset resolves the installed/global mm-harness (prod). Handing the
|
|
24
|
+
# invocation over here, before any dependency work, lets the dev checkout fully
|
|
25
|
+
# own the run. The self-path guard prevents an exec loop when MM_HARNESS_BIN
|
|
26
|
+
# already points at this script — including via a symlink (both sides are resolved
|
|
27
|
+
# to their real paths before comparing).
|
|
28
|
+
if [ -n "${MM_HARNESS_BIN:-}" ]; then
|
|
29
|
+
self_real="$SCRIPT_DIR/$(basename "$SOURCE")"
|
|
30
|
+
# Resolve MM_HARNESS_BIN through any symlink chain so a symlink-to-self is caught.
|
|
31
|
+
mm_bin_src="$MM_HARNESS_BIN"
|
|
32
|
+
while [ -L "$mm_bin_src" ]; do
|
|
33
|
+
mm_bin_dir="$(cd "$(dirname "$mm_bin_src")" && pwd -P)"
|
|
34
|
+
mm_bin_target="$(readlink "$mm_bin_src")"
|
|
35
|
+
if [[ "$mm_bin_target" == /* ]]; then
|
|
36
|
+
mm_bin_src="$mm_bin_target"
|
|
37
|
+
else
|
|
38
|
+
mm_bin_src="$mm_bin_dir/$mm_bin_target"
|
|
39
|
+
fi
|
|
40
|
+
done
|
|
41
|
+
bin_real_dir="$(cd "$(dirname "$mm_bin_src")" 2>/dev/null && pwd -P || true)"
|
|
42
|
+
bin_real="${bin_real_dir:+$bin_real_dir/$(basename "$mm_bin_src")}"
|
|
43
|
+
if [ "$bin_real" != "$self_real" ]; then
|
|
44
|
+
if [ ! -x "$MM_HARNESS_BIN" ]; then
|
|
45
|
+
echo "mm-harness: MM_HARNESS_BIN is not an executable: $MM_HARNESS_BIN" >&2
|
|
46
|
+
echo " Next: point MM_HARNESS_BIN at a checkout's bin/mm-harness, or unset it to use the global install" >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
exec "$MM_HARNESS_BIN" "$@"
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
ENSURE_DEPS="$RUNNER_DIR/adapters/shared/ensure-runner-deps.sh"
|
|
23
54
|
if [ -f "$ENSURE_DEPS" ]; then
|
|
24
55
|
# shellcheck disable=SC1090
|
|
25
56
|
bash "$ENSURE_DEPS" "$RUNNER_DIR"
|
|
26
57
|
fi
|
|
27
58
|
|
|
28
|
-
ENTRY_TS="$RUNNER_DIR/
|
|
59
|
+
ENTRY_TS="$RUNNER_DIR/src/mm-harness-cli.ts"
|
|
29
60
|
ENTRY_DIST="$RUNNER_DIR/dist/mm-harness-cli.js"
|
|
30
61
|
|
|
31
62
|
find_protocol_root() {
|
package/docs/CLI-SPEC.md
CHANGED
|
@@ -36,8 +36,8 @@ exhaustive —
|
|
|
36
36
|
- **REMOVE** — name/bin/subcommand deleted in the wave; **requires a one-line justification** (needs Arthur's sign-off).
|
|
37
37
|
|
|
38
38
|
**No row may be unmapped.** An unmapped row means the refactor is not allowed to
|
|
39
|
-
proceed. Source of truth: the bins' `case` statements + the naming audit
|
|
40
|
-
|
|
39
|
+
proceed. Source of truth: the bins' `case` statements + the naming audit.
|
|
40
|
+
Every row is real.
|
|
41
41
|
|
|
42
42
|
## Surface A — `metamask-recipe` typed CLI (`runner/src/cli.ts`)
|
|
43
43
|
|
|
@@ -913,3 +913,42 @@ The fleet is just another agent-grade caller:
|
|
|
913
913
|
slot's prepare hook calls the same verb with slot context; dispatch scales it
|
|
914
914
|
across the fleet.
|
|
915
915
|
|
|
916
|
+
## Appendix — Extension runtime lifecycle (internal notes)
|
|
917
|
+
|
|
918
|
+
Internal implementation notes for the Extension runtime lifecycle — the
|
|
919
|
+
self-healing path that gets a checkout from "installed" to "a live, verified
|
|
920
|
+
extension under CDP control". These are **not** a public command surface: the
|
|
921
|
+
probes below are internal functions, composed for you by `launch --verify` and by
|
|
922
|
+
the readiness commands (`doctor --fix`, `verify`). The runner is the source of
|
|
923
|
+
truth for Extension harness injection, readiness decisions, extension-id
|
|
924
|
+
resolution, and live CDP health checks.
|
|
925
|
+
|
|
926
|
+
Public entry points:
|
|
927
|
+
|
|
928
|
+
- **`install`** writes the Extension runtime overlay under the configured harness
|
|
929
|
+
root. CI/agents run it explicitly; the daily-loop commands auto-ensure it.
|
|
930
|
+
- **`verify`** confirms the overlay is present and healthy — a live CDP health
|
|
931
|
+
probe when a runtime is reachable, no launch.
|
|
932
|
+
- **`launch --verify`** installs the overlay if missing, launches/attaches the
|
|
933
|
+
extension, and polls CDP until the runtime is ready.
|
|
934
|
+
- **`doctor` / `doctor --fix`** report readiness and (with `--fix`) run the
|
|
935
|
+
healing steps below WITHOUT starting the app.
|
|
936
|
+
|
|
937
|
+
Internal lifecycle stages, composed in order (each idempotent, each reporting the
|
|
938
|
+
cheapest next action so the path converges rather than rebuilding from scratch):
|
|
939
|
+
|
|
940
|
+
- **Extension-id resolution** — resolves the deterministic unpacked extension id
|
|
941
|
+
from `dist/chrome/manifest.json`, optionally verified against a live CDP target.
|
|
942
|
+
Runs first; every later stage keys off this id.
|
|
943
|
+
- **Readiness decision** — inspects the checkout + live browser and returns the
|
|
944
|
+
cheapest next action (`install`, `build`, `relaunch`, or `ready`) plus the
|
|
945
|
+
concrete `actions[]` to execute.
|
|
946
|
+
- **Runtime launch** — launches Chrome with the installed harness helper, seeds
|
|
947
|
+
the wallet fixture, and runs live smoke verification. Two tiers: reuse the
|
|
948
|
+
existing dist (quick relaunch), or the clean-build path (clear webpack cache,
|
|
949
|
+
start the harness-owned watcher, wait for a clean compile, then launch + verify).
|
|
950
|
+
- **Convergence** — converges the live browser to exactly one healthy `home.html`
|
|
951
|
+
tab (closing strays, reopening if needed) and confirms it with the health probe.
|
|
952
|
+
- **Health probe** — read-only liveness probe for the running extension over CDP;
|
|
953
|
+
the final gate of convergence and the standalone answer for `verify`.
|
|
954
|
+
|
package/docs/architecture.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# MetaMask Recipe Runner Architecture
|
|
2
2
|
|
|
3
|
+
**Control flows DOWN only — a DAG, never a loop.**
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
bin/mm-harness ← entry (thin bootstrap)
|
|
7
|
+
│
|
|
8
|
+
▼
|
|
9
|
+
┌───────────────────────────────────────────────┐
|
|
10
|
+
│ src/ THE BRAIN — all TypeScript │
|
|
11
|
+
│ CLI · decisions · state machines · run │
|
|
12
|
+
│ engine · healing/errors · evidence │
|
|
13
|
+
└───────────────────────────────────────────────┘
|
|
14
|
+
│ spawns │ reads
|
|
15
|
+
▼ ▼
|
|
16
|
+
adapters/<platform>/ library/
|
|
17
|
+
DEVICE LEAVES (shell) VOCABULARY (data)
|
|
18
|
+
one op · args in · recipes · actions ·
|
|
19
|
+
result out · exit flows — pure JSON/mjs
|
|
20
|
+
(yarn-setup, start-metro,
|
|
21
|
+
open-device, xcrun, adb,
|
|
22
|
+
webpack, chrome)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| dir | is | rule |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| `bin/` | entry | one thin bootstrap |
|
|
28
|
+
| `src/` | the brain | ALL TypeScript, ALL decisions/sequencing |
|
|
29
|
+
| `adapters/<platform>/` | device leaves | one op each · never orchestrates · **never calls `mm-harness`** |
|
|
30
|
+
| `library/` | vocabulary | pure recipe/action/flow data |
|
|
31
|
+
|
|
32
|
+
**The one rule everything follows:** nothing under `adapters/` or `library/` ever calls `mm-harness`. TS orchestrates and spawns leaves; leaves do one device op and exit; vocabulary is data. (External callers — farm hooks, skills, overlay delegate — invoking `mm-harness` at the top level is fine; the ban is on the harness's OWN scripts calling back in.)
|
|
33
|
+
|
|
34
|
+
**Why:** every past mess (half-wired porcelain, commands referenced-but-unbuilt, stub tests faking the thing under test) came from control looping back up. Down-only makes that class of bug unrepresentable — and means less code.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
3
38
|
This repo is the MetaMask-specific adapter layer for Recipe Protocol v1. It is
|
|
4
39
|
not the protocol engine, not a skills repo, not a slot farm, and not product
|
|
5
40
|
code. Its job is to publish reviewable MetaMask capabilities and run them
|
|
@@ -21,9 +56,9 @@ doing more than parsing flags and calling `mm-harness`, that logic
|
|
|
21
56
|
belongs in this runner instead. Concrete example in flight: the
|
|
22
57
|
`recipe-harness` skill currently locates and execs runner internals in
|
|
23
58
|
hundreds of lines of bash (resolve runner source, dispatch to
|
|
24
|
-
`
|
|
59
|
+
`adapters/<platform>/{inject,cleanup}.{sh,mjs}` — `.sh` for Mobile/Core,
|
|
25
60
|
`.mjs` for Extension); the fix is a
|
|
26
|
-
[`mm-harness <install|verify|cleanup|live>`](
|
|
61
|
+
[`mm-harness <install|verify|cleanup|live>`](CLI-SPEC.md) command here, so the
|
|
27
62
|
skill thins to a few lines that call it. Same pattern applies to every other
|
|
28
63
|
`recipe-*` skill over time.
|
|
29
64
|
|
|
@@ -32,10 +67,10 @@ skill thins to a few lines that call it. Same pattern applies to every other
|
|
|
32
67
|
|
|
33
68
|
| Extension | Where | Use for | Why |
|
|
34
69
|
|---|---|---|---|
|
|
35
|
-
| `.ts` | `
|
|
36
|
-
| `.mjs` | `library/actions/**`, `
|
|
70
|
+
| `.ts` | `src/**` | CLI parsing, manifests, adapter binding, runtime decisions — typed/testable/shared logic | Compiled and typed; the maintainable core that everything else should grow into |
|
|
71
|
+
| `.mjs` | `library/actions/**`, `adapters/**`, `scripts/**` | Standalone action adapters and injected runtime helpers | Run-anywhere with zero build step, whether invoked from a published package or a raw checkout |
|
|
37
72
|
| `.cjs` | scattered, quarantined | Compatibility islands: portable `require()` from shell, bridge code for older runtime contexts | Only when the runtime context makes ESM brittle — not a default choice |
|
|
38
|
-
| `.sh` | `bin/`, `
|
|
73
|
+
| `.sh` | `bin/`, `adapters/{mobile,extension,core}/`, `adapters/shared/` | Thin OS/device glue at the edge: `simctl`, `adb`, Chrome process flags, git-exclude, filesystem setup | Must run before/without Node business logic; never recipe graph execution or MetaMask domain semantics |
|
|
39
74
|
|
|
40
75
|
The mix is bash-heavy today because sandbox setup crosses OS/device boundaries
|
|
41
76
|
(see "Why there are shell scripts" below) — that is current reality, not the
|
|
@@ -85,15 +120,15 @@ summary.json · trace.json · artifact-manifest.json · screenshots/logs
|
|
|
85
120
|
|
|
86
121
|
**Dependency direction is one-way and provable.** The runner *depends on*
|
|
87
122
|
`@farmslot/recipe-harness` + `@farmslot/protocol` (see `package.json`), and
|
|
88
|
-
`
|
|
123
|
+
`src/**` *imports* the generic contracts rather than forking them:
|
|
89
124
|
|
|
90
|
-
- `
|
|
125
|
+
- `src/cli.ts` imports `RecipeRunResult` from `@farmslot/recipe-harness`
|
|
91
126
|
and delegates library `flows` to the harness CLI (`importRecipeHarnessCli`).
|
|
92
|
-
- `
|
|
127
|
+
- `src/runner.ts` wires `metamask.*` adapters INTO the farmslot
|
|
93
128
|
`RecipeRunner`; it does not implement graph execution.
|
|
94
|
-
- `
|
|
129
|
+
- `src/manifest.ts` loads *MetaMask* manifests typed by the *farmslot*
|
|
95
130
|
protocol document type.
|
|
96
|
-
- `
|
|
131
|
+
- `src/recording-target.ts` is a MetaMask provider over the farmslot
|
|
97
132
|
`RecordingTarget` contract.
|
|
98
133
|
|
|
99
134
|
**The invariant both repos assert:** farmslot stays MetaMask-free; the runner
|
|
@@ -104,7 +139,7 @@ generic (farmslot); encodes MetaMask app knowledge = runner.
|
|
|
104
139
|
> Note on naming: "harness" refers to the tool (`mm-harness`) and the generic
|
|
105
140
|
> engine package (`@farmslot/recipe-harness`). The per-checkout files the tool
|
|
106
141
|
> installs into a target are the **runtime overlay** (`install`/`verify`/
|
|
107
|
-
> `cleanup`/`live`), never "the harness" — see [
|
|
142
|
+
> `cleanup`/`live`), never "the harness" — see [CLI-SPEC.md](CLI-SPEC.md).
|
|
108
143
|
|
|
109
144
|
## One-minute model
|
|
110
145
|
|
|
@@ -141,8 +176,8 @@ is the main way to understand the repository.
|
|
|
141
176
|
|
|
142
177
|
| Subsystem | Question it answers | Primary files | Should contain | Should not contain |
|
|
143
178
|
|---|---|---|---|---|
|
|
144
|
-
| Recipe capability/execution | “What can a MetaMask recipe do, and how does a node execute?” | `library/manifests/`, `library/recipes/`, `
|
|
145
|
-
| Runtime lifecycle / sandbox helpers | “How do I give an agent an isolated app session that is ready to inspect or run recipes?” | `
|
|
179
|
+
| Recipe capability/execution | “What can a MetaMask recipe do, and how does a node execute?” | `library/manifests/`, `library/recipes/`, `src/runner.ts`, `src/adapters.ts`, `src/live-adapter-contract.ts`, `library/actions/` | action manifests, domain actions, UI transport binding, adapter outputs, proof semantics | Metro startup, Chrome process flags, simulator boot, git-exclude/rsync cleanup |
|
|
180
|
+
| Runtime lifecycle / sandbox helpers | “How do I give an agent an isolated app session that is ready to inspect or run recipes?” | `adapters/porcelain/`, `adapters/{mobile,extension,core}/`, `adapters/shared/` | install/sync harness, start/reuse Metro or Chrome, prewarm bundles, open Extension full-screen or popup-style, prepare dedicated profiles/fixtures, check build/runtime health, cleanup local files | new recipe schema, graph traversal, MetaMask business semantics, task-specific proof logic |
|
|
146
181
|
|
|
147
182
|
When reviewing a change, first decide which subsystem it touches. Recipe changes
|
|
148
183
|
should be validated against manifests and action artifacts. Runtime lifecycle changes should be validated by install/launch/live/verify
|
|
@@ -168,29 +203,26 @@ describes **how an agent should work**, it belongs in skills.
|
|
|
168
203
|
|
|
169
204
|
| Path | Responsibility |
|
|
170
205
|
|---|---|
|
|
171
|
-
| `
|
|
172
|
-
| `
|
|
173
|
-
| `
|
|
174
|
-
| `
|
|
175
|
-
| `runner/src/runner.ts` | Creates the Recipe runner by combining shared core/ui adapters with MetaMask live adapters. Enables the Recipe HUD metadata. |
|
|
176
|
-
| `runner/src/adapters.ts` | MetaMask adapter binding and `ui.*` transport selection for Mobile vs Extension. Refuses static placeholders for live-only proof actions. |
|
|
177
|
-
| `runner/src/live-adapter-contract.ts` | Script adapter contract and lookup rules for `library/actions/<platform>/<domain>/*.mjs`. |
|
|
206
|
+
| `src/cli.ts` | Typed command handlers: manifests, actions, doctor, runtime health/decision/launch, `run`. |
|
|
207
|
+
| `src/runner.ts` | Creates the Recipe runner by combining shared core/ui adapters with MetaMask live adapters. Enables the Recipe HUD metadata. |
|
|
208
|
+
| `src/adapters.ts` | MetaMask adapter binding and `ui.*` transport selection for Mobile vs Extension. Refuses static placeholders for live-only proof actions. |
|
|
209
|
+
| `src/live-adapter-contract.ts` | Script adapter contract and lookup rules for `library/actions/<platform>/<domain>/*.mjs`. |
|
|
178
210
|
| `library/manifests/*.action-manifest.json` | Reviewable capability contract. A recipe may only call declared actions. |
|
|
179
211
|
| `library/actions/mobile/` | Mobile action implementations. Talks to the runner bridge and app-exposed `globalThis.__AGENTIC__` hooks. |
|
|
180
212
|
| `library/actions/extension/` | Extension action implementations. Talks to Chrome/extension pages over CDP. |
|
|
181
|
-
| `
|
|
182
|
-
| `
|
|
183
|
-
| `
|
|
184
|
-
| `
|
|
185
|
-
| `
|
|
186
|
-
| `
|
|
213
|
+
| `adapters/mobile/inject.sh` | Installs/syncs the Mobile runtime overlay under the configured harness root and protects cleanup/git-exclude behavior. |
|
|
214
|
+
| `adapters/extension/inject.mjs` | Installs/syncs Extension runtime helpers under the configured harness root. |
|
|
215
|
+
| `adapters/mobile/` | Runner-owned Mobile launch/live/inject/cleanup and verify helpers copied into installed harnesses. |
|
|
216
|
+
| `adapters/extension/` | Runner-owned Extension launch/live/watch/windows/wallet-state/readiness helpers (orchestration) and verify (recipe) copied into installed harnesses. |
|
|
217
|
+
| `adapters/shared/path-defaults.json` | Single source for default `recipeHarnessRoot` and `recipeRuntimeDir`. |
|
|
218
|
+
| `adapters/shared/harness-path.sh`, `src/paths.ts` | Shell and TypeScript accessors for those defaults plus validation. |
|
|
187
219
|
| `library/recipes/` | Reusable smoke/action-validation recipes only. Task-specific proof recipes stay task-local. |
|
|
188
220
|
| `library/library.json`, `library/flows/` | Canonical recipe library: minimal, stable flows recipes can `call`. Personal/team libraries shadow it by default — see [Recipe Libraries](recipe-libraries.md). |
|
|
189
221
|
| `docs/` | Runner architecture, contracts, and operational conventions. |
|
|
190
222
|
|
|
191
223
|
## Runtime paths and installed harnesses
|
|
192
224
|
|
|
193
|
-
Defaults are centralized in `
|
|
225
|
+
Defaults are centralized in `adapters/shared/path-defaults.json`:
|
|
194
226
|
|
|
195
227
|
```json
|
|
196
228
|
{
|
|
@@ -210,7 +242,7 @@ Install commands write a small runtime package into the target checkout:
|
|
|
210
242
|
<target>/<recipeHarnessRoot>/<adapter>/
|
|
211
243
|
manifest.json installed source/revision/cleanup metadata
|
|
212
244
|
action-manifest.json snapshot of the adapter manifest
|
|
213
|
-
runner/bin/
|
|
245
|
+
runner/bin/mm-harness delegate back to the resolved runner source
|
|
214
246
|
runner/recipes/ reusable recipe snapshot
|
|
215
247
|
scripts/ adapter runtime helpers copied from this repo
|
|
216
248
|
```
|
|
@@ -222,10 +254,10 @@ this runner.
|
|
|
222
254
|
## Recipe execution vs sandbox lifecycle
|
|
223
255
|
|
|
224
256
|
`mm-harness run <recipe.json> --adapter ...` is the recipe path. It creates
|
|
225
|
-
a shared Recipe runner (`
|
|
257
|
+
a shared Recipe runner (`src/runner.ts`), validates the recipe against the
|
|
226
258
|
manifest, executes nodes, and writes artifacts. If a bug is about action fields,
|
|
227
259
|
trace output, adapter semantics, or whether a recipe proves a claim, start in
|
|
228
|
-
`library/manifests/`, `
|
|
260
|
+
`library/manifests/`, `src/`, `library/actions/`, and `library/recipes/`.
|
|
229
261
|
|
|
230
262
|
`prepare`, `launch`, `live`, `verify`, `status`, `decision`, and `ready` are
|
|
231
263
|
sandbox lifecycle paths. They give the agent a reproducible local app session:
|
|
@@ -233,8 +265,7 @@ Mobile with Metro/dev-client/simulator and the bridge online; Extension with an
|
|
|
233
265
|
isolated browser profile, unpacked extension loaded, and a known home/popup-style
|
|
234
266
|
UI target. If a bug is about Metro, bundle prewarm, simulator launch, Chrome CDP,
|
|
235
267
|
Extension full-screen vs popup presentation, build freshness, wallet fixture
|
|
236
|
-
placement, git-exclude, or cleanup, start in `
|
|
237
|
-
`orchestration/{mobile,extension,core}/` and `runner/{mobile,extension}/`.
|
|
268
|
+
placement, git-exclude, or cleanup, start in `adapters/{mobile,extension,core}/`.
|
|
238
269
|
|
|
239
270
|
Do not put recipe graph traversal into shell scripts. Shell scripts may prepare
|
|
240
271
|
or inspect the sandboxed runtime, then delegate graph execution to
|
|
@@ -247,7 +278,7 @@ These names are easy to mix up; they are different concerns.
|
|
|
247
278
|
| Term | What it is | Why it exists |
|
|
248
279
|
|---|---|---|
|
|
249
280
|
| Recipe HUD | A visual overlay driven by Recipe runner metadata (`intent`, current node, status). | Makes screenshots/videos explain what the recipe is doing without exposing secrets. |
|
|
250
|
-
| Mobile bridge | Runner-side CDP/Hermes bridge process under `
|
|
281
|
+
| Mobile bridge | Runner-side CDP/Hermes bridge process under `adapters/mobile/bridge-runtime/`. | Lets the runner call app-exposed commands, read state, press UI targets, and capture status from React Native. |
|
|
251
282
|
| `globalThis.__AGENTIC__` | Development-only in-app command surface exposed by the Mobile overlay/patch. | Gives the bridge a stable API for route/status/wallet/UI operations when the app lacks a built-in automation API. |
|
|
252
283
|
| Extension CDP hooks | Chrome DevTools Protocol access to extension pages/background state hooks. | Lets the runner inspect/drive the unpacked Extension without patching product source. |
|
|
253
284
|
|
|
@@ -260,10 +291,10 @@ Mobile has the most moving parts because React Native does not expose a browser
|
|
|
260
291
|
DOM by default.
|
|
261
292
|
|
|
262
293
|
```text
|
|
263
|
-
mm-
|
|
264
|
-
│
|
|
294
|
+
mm-harness launch ios|android
|
|
295
|
+
│ prepareMobile() in-process → yarn-setup / start-metro / open-device leaves
|
|
265
296
|
▼
|
|
266
|
-
|
|
297
|
+
adapters/mobile/bridge-runtime/cdp-bridge.cjs
|
|
267
298
|
│ connects to Hermes / RN debug runtime
|
|
268
299
|
▼
|
|
269
300
|
globalThis.__AGENTIC__ inside the app
|
|
@@ -295,7 +326,7 @@ Extension does not need an in-product source patch. The runner works through an
|
|
|
295
326
|
unpacked `dist/chrome` build and Chrome CDP.
|
|
296
327
|
|
|
297
328
|
```text
|
|
298
|
-
mme-recipe /
|
|
329
|
+
mme-recipe / adapters/extension/*.sh
|
|
299
330
|
│ checks dist freshness, build health, fixture/profile state
|
|
300
331
|
▼
|
|
301
332
|
Chrome for Testing with --load-extension=<runtime-dist>
|
|
@@ -329,7 +360,7 @@ Allowed in shell:
|
|
|
329
360
|
Not allowed in shell:
|
|
330
361
|
|
|
331
362
|
- Recipe v1 graph execution;
|
|
332
|
-
- MetaMask domain semantics that can live in `
|
|
363
|
+
- MetaMask domain semantics that can live in `src/**/*.ts` or `library/actions/**/*.mjs`;
|
|
333
364
|
- duplicated action manifest logic;
|
|
334
365
|
- product-specific business decisions beyond runtime boot/health checks.
|
|
335
366
|
|
|
@@ -6,9 +6,9 @@ package without requiring target app builds to transpile runner code.
|
|
|
6
6
|
|
|
7
7
|
## Extension rules
|
|
8
8
|
|
|
9
|
-
- `
|
|
9
|
+
- `src/**/*.ts` — typed runner core: CLI parsing, manifests, adapter binding,
|
|
10
10
|
runtime decisions, and shared helper logic.
|
|
11
|
-
- `library/actions/**/*.mjs`, `
|
|
11
|
+
- `library/actions/**/*.mjs`, `adapters/**/*.mjs`, and `scripts/**/*.mjs` —
|
|
12
12
|
standalone ESM modules that Node executes directly with no build step. Use
|
|
13
13
|
these for action adapters and small injected/runtime helpers.
|
|
14
14
|
- `*.cjs` — compatibility islands only. Keep these quarantined for helper code
|
|
@@ -31,6 +31,6 @@ The mix is intentional only when the boundary is clear:
|
|
|
31
31
|
4. Shell stays at the edge for host/device commands.
|
|
32
32
|
|
|
33
33
|
If a file crosses those boundaries, move the logic inward: shell should call a
|
|
34
|
-
Node module, standalone `.mjs` should become typed `
|
|
34
|
+
Node module, standalone `.mjs` should become typed `src/**/*.ts` when it grows
|
|
35
35
|
shared domain logic, and new compatibility needs should be documented before
|
|
36
36
|
adding another `.cjs` file.
|
|
@@ -8,7 +8,7 @@ import { mnemonicToAccount, privateKeyToAccount } from 'viem/accounts';
|
|
|
8
8
|
// this adapter under the bundled tsx (see commandFor/importsSourceTypescript in
|
|
9
9
|
// src/live-adapter-contract.ts). The core adapter dynamic-imports the perps
|
|
10
10
|
// controller TypeScript at runtime, so it MUST run under tsx, not plain node.
|
|
11
|
-
import { walletFixturePath } from '../../../../
|
|
11
|
+
import { walletFixturePath } from '../../../../src/index.ts';
|
|
12
12
|
|
|
13
13
|
// Shared headless instantiation for the MetaMask `core` adapter.
|
|
14
14
|
//
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
extensionIdPath,
|
|
11
11
|
recipeHarnessPath,
|
|
12
12
|
walletFixturePath,
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
captureActiveRecipeRecordingSnapshot,
|
|
14
|
+
} from '../../../../src/index.ts';
|
|
15
15
|
|
|
16
16
|
// Resolve the Farmslot harness through normal package dependencies by default.
|
|
17
17
|
// Local Farmslot source is only a dev override handled by src/paths.ts.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { runAdapter, withExtensionPage } from '../platform/cdp.mjs';
|
|
3
|
-
import { walletFixturePath } from '../../../../
|
|
3
|
+
import { walletFixturePath } from '../../../../src/index.ts';
|
|
4
4
|
|
|
5
5
|
async function fixturePassword(projectRoot) {
|
|
6
6
|
const candidates = [
|
|
@@ -31,7 +31,7 @@ function bridgeScript(input) {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function runtimeDir() {
|
|
34
|
-
return fileURLToPath(new URL('
|
|
34
|
+
return fileURLToPath(new URL('../../../../adapters/mobile/bridge-runtime', import.meta.url));
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export function bridgeEnv(input) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { bridgeCommand, runAdapter } from '../platform/bridge.mjs';
|
|
3
|
-
import { walletFixturePath } from '../../../../
|
|
3
|
+
import { walletFixturePath } from '../../../../src/index.ts';
|
|
4
4
|
|
|
5
5
|
async function fixturePassword(projectRoot) {
|
|
6
6
|
const candidates = [
|
|
@@ -3,7 +3,7 @@ import { spawn } from 'node:child_process';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { bridgeCommand, bridgeEnv, runAdapter } from '../platform/bridge.mjs';
|
|
6
|
-
import { walletFixturePath } from '../../../../
|
|
6
|
+
import { walletFixturePath } from '../../../../src/index.ts';
|
|
7
7
|
|
|
8
8
|
async function fixtureProfile(projectRoot) {
|
|
9
9
|
const candidates = [
|
|
@@ -109,7 +109,7 @@ function setupWalletScript() {
|
|
|
109
109
|
if (process.env.METAMASK_RECIPE_MOBILE_SETUP_WALLET_SCRIPT) {
|
|
110
110
|
return process.env.METAMASK_RECIPE_MOBILE_SETUP_WALLET_SCRIPT;
|
|
111
111
|
}
|
|
112
|
-
return fileURLToPath(new URL('
|
|
112
|
+
return fileURLToPath(new URL('../../../../adapters/mobile/bridge-runtime/setup-wallet.sh', import.meta.url));
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
function runSetupWallet(input, fixture) {
|
package/library/library.json
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"kind": "recipe-library",
|
|
3
3
|
"schema_version": 1,
|
|
4
4
|
"name": "metamask",
|
|
5
|
-
"owner": "
|
|
5
|
+
"owner": "mm-harness-runner",
|
|
6
6
|
"description": "Canonical MetaMask recipe library: minimal, stable flows every recipe can compose. Team and personal libraries layer on top and win resolution by default."
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeeed/metamask-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mm-harness": "bin/mm-harness"
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"dev:link-farmslot": "node scripts/link-local-farmslot.mjs",
|
|
10
10
|
"check": "node scripts/check.mjs",
|
|
11
|
-
"self-test": "
|
|
11
|
+
"self-test": "bin/mm-harness self-test",
|
|
12
12
|
"manifest:mobile": "bin/mm-harness actions --raw --adapter mobile --json",
|
|
13
13
|
"manifest:extension": "bin/mm-harness actions --raw --adapter extension --json",
|
|
14
14
|
"check:syntax": "find . -name '*.mjs' -print0 | xargs -0 -n1 node --check"
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
"@types/node": "^22.0.0",
|
|
25
25
|
"typescript": "^5.6.0"
|
|
26
26
|
},
|
|
27
|
-
"main": "./
|
|
28
|
-
"types": "./
|
|
27
|
+
"main": "./src/index.ts",
|
|
28
|
+
"types": "./src/index.ts",
|
|
29
29
|
"exports": {
|
|
30
30
|
".": {
|
|
31
|
-
"types": "./
|
|
32
|
-
"import": "./
|
|
31
|
+
"types": "./src/index.ts",
|
|
32
|
+
"import": "./src/index.ts"
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"publishConfig": {
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
},
|
|
38
38
|
"files": [
|
|
39
39
|
"bin",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
40
|
+
"src",
|
|
41
|
+
"adapters",
|
|
42
42
|
"library",
|
|
43
43
|
"scripts/completions.sh",
|
|
44
44
|
"scripts/install-completions.sh",
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import { execFileSync } from 'node:child_process';
|
|
4
4
|
import crypto from 'node:crypto';
|
|
5
5
|
import fs from 'node:fs';
|
|
6
|
-
import os from 'node:os';
|
|
7
6
|
import path from 'node:path';
|
|
8
7
|
import {
|
|
9
8
|
depsCheck,
|
|
@@ -11,7 +10,7 @@ import {
|
|
|
11
10
|
recordDepsBaseline,
|
|
12
11
|
type DepsCheck,
|
|
13
12
|
} from '@farmslot/recipe-harness/runtime/deps-readiness';
|
|
14
|
-
import { recipeWatchLogCandidates } from '../../
|
|
13
|
+
import { recipeHarnessPath, recipeWatchLogCandidates } from '../../paths.ts';
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* Deterministic runtime-readiness decision for the MetaMask Extension.
|
|
@@ -181,10 +180,11 @@ function webpackFingerprint(target: string): { gitHead: string; fingerprint: str
|
|
|
181
180
|
return { gitHead: git(target, ['rev-parse', 'HEAD']) ?? 'unknown', fingerprint: hash.digest('hex') };
|
|
182
181
|
}
|
|
183
182
|
|
|
184
|
-
// ── per-checkout baseline store (
|
|
183
|
+
// ── per-checkout baseline store (checkout-local; not written into the repo) ──
|
|
184
|
+
// State lives under the checkout's own harness dir so it is scoped to the
|
|
185
|
+
// checkout, survives /tmp cleanup, and is not in a world-writable directory.
|
|
185
186
|
function stateDir(target: string): string {
|
|
186
|
-
|
|
187
|
-
return path.join(os.tmpdir(), 'metamask-recipe-decision', key);
|
|
187
|
+
return recipeHarnessPath(target, 'extension', 'decision-state');
|
|
188
188
|
}
|
|
189
189
|
|
|
190
190
|
function readBaseline(target: string, name: string): Record<string, unknown> | null {
|
|
@@ -4,7 +4,7 @@ import { spawn } from 'node:child_process';
|
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
|
|
7
|
-
import { importRecipeHarnessRuntimeBrowserExtension, importRecipeHarnessRuntimeCdp, recipeRuntimeDir, resolveLocalProtocolRoot, resolveRequiredLocalProtocolRoot, runnerDir } from '../../
|
|
7
|
+
import { importRecipeHarnessRuntimeBrowserExtension, importRecipeHarnessRuntimeCdp, recipeRuntimeDir, resolveLocalProtocolRoot, resolveRequiredLocalProtocolRoot, runnerDir } from '../../paths.ts';
|
|
8
8
|
|
|
9
9
|
// Runtime health uses package dependencies. Launching a host-managed validation
|
|
10
10
|
// browser remains a dev-only path because it needs pool/project scripts from a
|