@deeeed/metamask-harness 0.2.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 +161 -0
- package/README.md +140 -0
- package/bin/mm-harness +99 -0
- package/docs/CHEATSHEET.md +61 -0
- package/docs/CLI-SPEC.md +915 -0
- package/docs/MENTAL-MODEL.md +295 -0
- package/docs/architecture.md +367 -0
- package/docs/extension-runtime-commands.md +60 -0
- package/docs/harness-cli.md +43 -0
- package/docs/live-adapter-contract.md +188 -0
- package/docs/package-boundaries.md +47 -0
- package/docs/perps-flow-catalog.md +235 -0
- package/docs/recipe-libraries.md +95 -0
- package/docs/runtime-file-conventions.md +36 -0
- package/library/actions/core/perps/_controller.mjs +727 -0
- package/library/actions/core/perps/assert_orders.mjs +53 -0
- package/library/actions/core/perps/assert_positions.mjs +52 -0
- package/library/actions/core/perps/close_orders.mjs +97 -0
- package/library/actions/core/perps/close_positions.mjs +118 -0
- package/library/actions/core/perps/ensure_orders.mjs +40 -0
- package/library/actions/core/perps/ensure_positions.mjs +37 -0
- package/library/actions/core/perps/place_order.mjs +201 -0
- package/library/actions/core/perps/read_account.mjs +30 -0
- package/library/actions/core/perps/read_orders.mjs +27 -0
- package/library/actions/core/perps/read_positions.mjs +27 -0
- package/library/actions/core/perps/start_state.mjs +92 -0
- package/library/actions/core/perps/teardown_state.mjs +86 -0
- package/library/actions/extension/perps/assert_orders.mjs +11 -0
- package/library/actions/extension/perps/assert_positions.mjs +11 -0
- package/library/actions/extension/perps/close_orders.mjs +8 -0
- package/library/actions/extension/perps/close_positions.mjs +8 -0
- package/library/actions/extension/perps/ensure_orders.mjs +4 -0
- package/library/actions/extension/perps/ensure_positions.mjs +4 -0
- package/library/actions/extension/perps/perps.mjs +730 -0
- package/library/actions/extension/perps/place_order.mjs +7 -0
- package/library/actions/extension/perps/read_orders.mjs +4 -0
- package/library/actions/extension/perps/read_positions.mjs +3 -0
- package/library/actions/extension/platform/cdp.mjs +541 -0
- package/library/actions/extension/ui/navigate.mjs +44 -0
- package/library/actions/extension/wallet/ensure_unlocked.mjs +36 -0
- package/library/actions/extension/wallet/read_state.mjs +27 -0
- package/library/actions/extension/wallet/select_account.mjs +48 -0
- package/library/actions/extension/wallet/setup.mjs +35 -0
- package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +185 -0
- package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +1662 -0
- package/library/actions/mobile/bridge-runtime/cdp-bridge.cjs +686 -0
- package/library/actions/mobile/bridge-runtime/lib/cdp-eval.cjs +110 -0
- package/library/actions/mobile/bridge-runtime/lib/config.cjs +39 -0
- package/library/actions/mobile/bridge-runtime/lib/issue-capture.cjs +446 -0
- package/library/actions/mobile/bridge-runtime/lib/target-discovery.cjs +204 -0
- package/library/actions/mobile/bridge-runtime/lib/ws-client.cjs +108 -0
- package/library/actions/mobile/bridge-runtime/setup-wallet.sh +442 -0
- package/library/actions/mobile/perps/assert_orders.mjs +11 -0
- package/library/actions/mobile/perps/assert_positions.mjs +11 -0
- package/library/actions/mobile/perps/close_orders.mjs +8 -0
- package/library/actions/mobile/perps/close_positions.mjs +8 -0
- package/library/actions/mobile/perps/ensure_orders.mjs +4 -0
- package/library/actions/mobile/perps/ensure_positions.mjs +4 -0
- package/library/actions/mobile/perps/perps.mjs +709 -0
- package/library/actions/mobile/perps/place_order.mjs +7 -0
- package/library/actions/mobile/perps/read_orders.mjs +4 -0
- package/library/actions/mobile/perps/read_positions.mjs +3 -0
- package/library/actions/mobile/platform/bridge.mjs +283 -0
- package/library/actions/mobile/ui/navigate.mjs +38 -0
- package/library/actions/mobile/wallet/ensure_unlocked.mjs +107 -0
- package/library/actions/mobile/wallet/home.mjs +35 -0
- package/library/actions/mobile/wallet/read_state.mjs +40 -0
- package/library/actions/mobile/wallet/select_account.mjs +48 -0
- package/library/actions/mobile/wallet/setup.mjs +220 -0
- package/library/flows/perps.flows.json +64 -0
- package/library/library.json +7 -0
- package/library/manifests/core.action-manifest.json +1282 -0
- package/library/manifests/extension.action-manifest.json +1749 -0
- package/library/manifests/mobile.action-manifest.json +1753 -0
- package/library/recipes/action-validation.extension.recipe.json +417 -0
- package/library/recipes/action-validation.mobile.recipe.json +422 -0
- package/library/recipes/order-lifecycle.core.recipe.json +78 -0
- package/library/recipes/perps-lifecycle.recipe.json +194 -0
- package/library/recipes/read-markets.core.recipe.json +38 -0
- package/library/recipes/smoke.extension.recipe.json +31 -0
- package/library/recipes/smoke.mobile.recipe.json +31 -0
- package/library/recipes/trading-lifecycle.core.recipe.json +76 -0
- package/orchestration/compat-overlays/README.md +19 -0
- package/orchestration/compat-overlays/mobile/README.md +13 -0
- package/orchestration/compat-overlays/mobile/rn81-message-event-source.patch +42 -0
- package/orchestration/core/cleanup.sh +37 -0
- package/orchestration/core/inject.sh +154 -0
- package/orchestration/doctor.mjs +72 -0
- package/orchestration/extension/cleanup.mjs +60 -0
- package/orchestration/extension/console-tail.mjs +228 -0
- package/orchestration/extension/ensure-browser.sh +416 -0
- package/orchestration/extension/ensure-ready.ts +185 -0
- package/orchestration/extension/extension-id.ts +107 -0
- package/orchestration/extension/inject.mjs +266 -0
- package/orchestration/extension/launch-browser.cjs +216 -0
- package/orchestration/extension/launch.sh +175 -0
- package/orchestration/extension/live.sh +320 -0
- package/orchestration/extension/pin-remote-flags.cjs +45 -0
- package/orchestration/extension/readiness.mjs +414 -0
- package/orchestration/extension/refresh-build.sh +190 -0
- package/orchestration/extension/runtime-decision.ts +445 -0
- package/orchestration/extension/runtime.ts +407 -0
- package/orchestration/extension/seed-fixture.sh +177 -0
- package/orchestration/extension/sidepanel-toggle.sh +291 -0
- package/orchestration/extension/snapshot-dist.sh +84 -0
- package/orchestration/extension/start-watch.sh +339 -0
- package/orchestration/extension/wallet-fixture-state.cjs +1086 -0
- package/orchestration/lib/activate-repo-node.sh +144 -0
- package/orchestration/lib/cli-color.mjs +84 -0
- package/orchestration/lib/cli-commands.mjs +243 -0
- package/orchestration/lib/cli-home.mjs +354 -0
- package/orchestration/lib/cli-ux.sh +252 -0
- package/orchestration/lib/cli-version.mjs +123 -0
- package/orchestration/lib/ensure-runner-deps.sh +56 -0
- package/orchestration/lib/harness-path.sh +55 -0
- package/orchestration/lib/hash-helpers.sh +44 -0
- package/orchestration/lib/json-field.sh +23 -0
- package/orchestration/lib/log-tui.mjs +304 -0
- package/orchestration/lib/open-debug.mjs +317 -0
- package/orchestration/lib/path-defaults.json +4 -0
- package/orchestration/lib/progress.mjs +107 -0
- package/orchestration/lib/recipe-paths.mjs +26 -0
- package/orchestration/lib/resolve-farmslot-ports.sh +144 -0
- package/orchestration/manifest.json +358 -0
- package/orchestration/mobile/cleanup.sh +192 -0
- package/orchestration/mobile/deps-markers.ts +21 -0
- package/orchestration/mobile/inject.sh +681 -0
- package/orchestration/mobile/launch.sh +137 -0
- package/orchestration/mobile/live.sh +125 -0
- package/orchestration/mobile/runtime-decision.ts +292 -0
- package/orchestration/porcelain/metamask-recipe +99 -0
- package/orchestration/porcelain/mm-recipe +1591 -0
- package/orchestration/porcelain/mme-recipe +1181 -0
- package/package.json +59 -0
- package/runner/extension/verify.sh +511 -0
- package/runner/mobile/verify.sh +501 -0
- package/runner/src/adapters.ts +601 -0
- package/runner/src/cli.ts +1820 -0
- package/runner/src/commands/debug.ts +44 -0
- package/runner/src/commands/fixtures.ts +99 -0
- package/runner/src/commands/launch.ts +397 -0
- package/runner/src/commands/logs.ts +60 -0
- package/runner/src/commands/shared.ts +138 -0
- package/runner/src/completions-cache.ts +86 -0
- package/runner/src/doctor.ts +203 -0
- package/runner/src/harness.ts +516 -0
- package/runner/src/heal-bounds.ts +179 -0
- package/runner/src/index.ts +6 -0
- package/runner/src/live-adapter-contract.ts +274 -0
- package/runner/src/manifest.ts +47 -0
- package/runner/src/mm-harness-cli.ts +488 -0
- package/runner/src/paths.ts +198 -0
- package/runner/src/recording-target.ts +147 -0
- package/runner/src/run-recording.ts +329 -0
- package/runner/src/runner.ts +108 -0
- package/runner/src/types.ts +57 -0
- package/scripts/completions.sh +125 -0
- package/scripts/install-completions.sh +62 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# mm-harness — Mental Model (review first)
|
|
2
|
+
|
|
3
|
+
Read this before the code. It is the before→after map for the CLI refactor. Every
|
|
4
|
+
"today" command below is real (from `bin/mm-recipe`, `bin/mme-recipe`,
|
|
5
|
+
`runner/src/cli.ts`, and the `recipe-harness` skill) — nothing invented.
|
|
6
|
+
|
|
7
|
+
> Skimmable overview. The detailed contract — a complete capability inventory
|
|
8
|
+
> (every verb, with a fate), a per-verb spec, the caller audit, and the env-var
|
|
9
|
+
> audit — is in [CLI-SPEC.md](CLI-SPEC.md).
|
|
10
|
+
|
|
11
|
+
## The model in one paragraph
|
|
12
|
+
|
|
13
|
+
**`mm-harness` is built for the agent but easy for the human to use and
|
|
14
|
+
understand.** It is the one front door for the whole recipe loop. The agent gets
|
|
15
|
+
full depth (explicit flags, `--json`, ports, build tiers — machine-grade
|
|
16
|
+
determinism); the human gets short verbs, positional targets, good defaults,
|
|
17
|
+
completions, and teaching help/errors. Under it: the **engine** is
|
|
18
|
+
`@farmslot/recipe-harness` (generic graph execution, adapters, recording, CLI);
|
|
19
|
+
the **runner** (this repo) is the thin **MetaMask adapter** layer (manifests,
|
|
20
|
+
`metamask.*` live adapters, orchestration); the **runtime overlay** is the set of
|
|
21
|
+
files the tool installs into a target checkout (`install`/`verify`/`cleanup`).
|
|
22
|
+
The runner never re-implements engine logic — it imports it. The agent
|
|
23
|
+
composition loop is the harness's thesis made concrete: **discover** actions and
|
|
24
|
+
browse flows (`actions --json` / `flows --json`) → **call** one action in
|
|
25
|
+
isolation to verify it (`call <action> --json`) → **compose** a `recipe.json` →
|
|
26
|
+
**plan** before any device is touched (`run --plan`) → **run** → review
|
|
27
|
+
evidence (`summary.json` / `trace.json`). `run --plan` closes the loop: adapter-aware
|
|
28
|
+
validation (action existence, platform support, fixture preconditions) exits fast
|
|
29
|
+
with a reviewable plan artifact — wrong recipes fail before any device is touched.
|
|
30
|
+
|
|
31
|
+
## Organizing rule (Arthur)
|
|
32
|
+
|
|
33
|
+
Identify the MAIN commands a human types daily, then each subcommand — always
|
|
34
|
+
optimizing "how simple for the human," with advanced options for the agent and
|
|
35
|
+
good defaults for easy typing. Enforced rules, visible in every table below:
|
|
36
|
+
|
|
37
|
+
- **Grammar:** `mm-harness <verb> [target] [flags]`. Target is a positional
|
|
38
|
+
(`ios` | `android` | `extension`) — the human form. The equivalent explicit
|
|
39
|
+
flag (`--platform …`) is the agent form.
|
|
40
|
+
- **Depth lives in FLAGS, never in extra command names.** If a daily task needs
|
|
41
|
+
>1 flag (or >1 step) for a human, the default is wrong — a `[DEFAULT-GAP]`.
|
|
42
|
+
- **No env-var prefixes for humans.** `VAR=x mm-harness …` is agent/CI syntax
|
|
43
|
+
only; a human-typed value that has no flag/config home is an `[ENV-GAP]`.
|
|
44
|
+
- **One bin, clean break.** End state has exactly one command, `mm-harness`. The
|
|
45
|
+
`metamask-recipe` / `mm-recipe` / `mme-recipe` names and the `harness <verb>`
|
|
46
|
+
subcommand form are REMOVED in the same coordinated wave; their capabilities
|
|
47
|
+
live at their final `mm-harness` home (Part 2 of the spec).
|
|
48
|
+
- **A verb's most common action is its default action.** `mm-harness flows` lists;
|
|
49
|
+
`mm-harness flows promote` is the explicit subcommand. Never force the user to
|
|
50
|
+
type `list` when listing is what the verb does by default.
|
|
51
|
+
- **Direct action names are not top-level verbs (REJECTED).** `mm-harness unlock`
|
|
52
|
+
is rejected — an open action vocabulary collides with the verb namespace; hot
|
|
53
|
+
actions get deliberately promoted to real verbs instead. Use
|
|
54
|
+
`mm-harness call unlock` (fuzzy short-name resolution to `metamask.wallet.unlock`
|
|
55
|
+
when unambiguous).
|
|
56
|
+
- **The overlay is per-checkout, git-ignored plumbing — humans never manage it.**
|
|
57
|
+
Daily verbs (`launch`, `run`) check for the overlay at startup and
|
|
58
|
+
auto-install it inline with a one-line notice on first run on that checkout.
|
|
59
|
+
`install` is the explicit form for CI, agents, and deterministic setup
|
|
60
|
+
(`--heal=off` on daily verbs disables the inline check and all healing).
|
|
61
|
+
- **Your slot's settings live in `agentic-runtime.json` — `doctor` explains them;
|
|
62
|
+
you never hunt for the file.** `doctor` prints every field (slotId, extensionId,
|
|
63
|
+
cdpPort, runtimeStart.*), its current value, its source (file / env var /
|
|
64
|
+
default), and exactly how to change it. Arthur's rule made concrete: no
|
|
65
|
+
knowledge lock-in about which file to edit.
|
|
66
|
+
- **Verbs are idempotent — they make reality match intent; the recovery command is
|
|
67
|
+
the normal command.** `launch` and `run` detect broken runtime state
|
|
68
|
+
(Metro dead, Chrome/CDP offline, stale tabs) and heal before proceeding (controlled
|
|
69
|
+
by `--heal`; default `auto` for `launch`, `infra-only` for `run`). The
|
|
70
|
+
agent does not need a separate recovery verb: re-running `mm-harness launch ios`
|
|
71
|
+
IS the recovery. `--json` reports what was healed in a `recovered:[...]` field
|
|
72
|
+
(stable codes). `recoverable:false` + `attemptedRecoveries[]` stop agent retry
|
|
73
|
+
loops when bounds are hit. `doctor --fix` repairs without launching when healing
|
|
74
|
+
alone is the goal.
|
|
75
|
+
|
|
76
|
+
## Status legend
|
|
77
|
+
|
|
78
|
+
| Tag | Meaning |
|
|
79
|
+
|---|---|
|
|
80
|
+
| **ROUTES-NOW** | Works today through `mm-harness` (this draft) |
|
|
81
|
+
| **STUB** | `mm-harness` verb exists but exits 2 and teaches the working command; spec'd in Part 2 |
|
|
82
|
+
| **ABSORB-LATER** | Capability folds into an `mm-harness` verb (spec'd in Part 2 with a maps-to row) |
|
|
83
|
+
| **KEEP-INTERNAL** | Still reachable, just not a user-facing verb |
|
|
84
|
+
| **REMOVE** | Name/bin/subcommand deleted in the refactor wave; callers updated in the same wave (needs sign-off) |
|
|
85
|
+
|
|
86
|
+
## Bin & name table (before → after)
|
|
87
|
+
|
|
88
|
+
| Before | Role today | After |
|
|
89
|
+
|---|---|---|
|
|
90
|
+
| `bin/metamask-recipe` | public typed CLI + platform passthrough | **REMOVE** — becomes `bin/mm-harness` (same entrypoint, one name); no alias kept |
|
|
91
|
+
| `metamask-recipe harness <verb>` | overlay lifecycle subcommand | **REMOVE** — verbs live top-level (`mm-harness install/verify/cleanup`); `live` dissolved into `launch --verify` |
|
|
92
|
+
| `bin/mm-recipe` | mobile porcelain (Metro/sim/bridge) | **REMOVE** — capabilities become `mm-harness` verbs (Part 2); impl kept internal |
|
|
93
|
+
| `bin/mme-recipe` | extension porcelain (Chrome/CDP) | **REMOVE** — capabilities become `mm-harness` verbs (Part 2); impl kept internal |
|
|
94
|
+
| `recipe-harness` skill (~812 lines bash) | overlay lifecycle | **REMOVE** — thins to a caller of `mm-harness` overlay verbs |
|
|
95
|
+
| `completions/_recipe` (zsh; completes `recipe mme-recipe mm-recipe`) | shell completion | **REMOVE** — replaced by bundled `mm-harness` completions (zsh + bash), auto-installed on setup |
|
|
96
|
+
|
|
97
|
+
**`bin/mm-harness`** is the one user bin. **No per-platform binaries** —
|
|
98
|
+
`mm-mobile-harness` / `mm-extension-harness` are rejected (recreates the
|
|
99
|
+
three-names problem). Platform = auto-detected context; the positional target
|
|
100
|
+
forces it; platform-specific needs are FLAGS on the same verb.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## BEFORE → AFTER by main command
|
|
105
|
+
|
|
106
|
+
Columns: **Human form** (bare verb / positional target; zero env prefixes;
|
|
107
|
+
defaults stated) · **Agent / advanced form** (explicit flags, `--json`) · **Status**.
|
|
108
|
+
|
|
109
|
+
### DAILY LOOP
|
|
110
|
+
|
|
111
|
+
#### `launch` — start the app (Metro/build + boot) · REAL (wave 3)
|
|
112
|
+
|
|
113
|
+
Auto-ensures runtime overlay before launching (installs inline with a one-line notice on first run; `--heal=off` to disable). **Idempotent + self-healing (default `--heal=auto`):** detects broken runtime state (Metro dead, Chrome/CDP offline, stale home tabs) and recovers before launching. The agent's recovery command is simply `mm-harness launch <target>` — no separate recovery verb. `--json` gains `"recovered": ["metro.restarted", ...]` (stable codes); `recoverable:false` + `attemptedRecoveries[]` stop retry loops. **`--verify`:** after launch, polls CDP/bridge until ready + runs smoke verify — implements the retired `live` sequence (zero capability lost). **Change detection:** quick launch (no `--build`) checks native/webpack build inputs; if changed → refuses with teaching error pointing at `--build`. Phase state-machine: `resolve → install → healthcheck → recover → launch → verify`.
|
|
114
|
+
|
|
115
|
+
| | |
|
|
116
|
+
|---|---|
|
|
117
|
+
| **Human form (mobile)** | `mm-harness launch ios` · `mm-harness launch android` — target **MANDATORY**; missing → teaching error: "specify ios or android" |
|
|
118
|
+
| **Human form (extension)** | `mm-harness launch` (no target; default `--fullscreen`; `--sidepanel` to open sidepanel mode) |
|
|
119
|
+
| **Quick vs full build** | bare `launch` = quick relaunch (no native/webpack build); `--build` = full build first |
|
|
120
|
+
| **Runway (mobile only)** | `--runway` runs a post-launch runway check; teaching error on extension |
|
|
121
|
+
| **`live` replacement** | `mm-harness launch ios --verify` (install overlay → launch → poll → smoke verify — never seeds fixtures) |
|
|
122
|
+
| **Agent / advanced** | `mm-harness launch --platform ios --device <udid> --build --verify --heal=off --json` |
|
|
123
|
+
|
|
124
|
+
| Today (real) | → mm-harness | Status |
|
|
125
|
+
|---|---|---|
|
|
126
|
+
| `mm-recipe ios` · `android` · `start` | `launch ios\|android` (positional, mandatory) | ABSORB-LATER |
|
|
127
|
+
| `mm-recipe up` | `launch ios --build` | ABSORB-LATER · [DEFAULT-GAP] tier hidden behind `MOBILE_PREFLIGHT_MODE=…` [ENV-GAP] |
|
|
128
|
+
| `mm-recipe refresh` · `reload` · `relaunch` | `launch ios\|android` (quick) | ABSORB-LATER |
|
|
129
|
+
| `mme-recipe rebuild` · `reopen` · `browser` · `launch` · `reload` · `reset` | `launch` (quick, extension) | ABSORB-LATER |
|
|
130
|
+
| `mme-recipe up` | `launch --build` (extension) | ABSORB-LATER |
|
|
131
|
+
| `mme-recipe watch` **then** `rebuild` | `launch --watch` (extension) | ABSORB-LATER · [DEFAULT-GAP] two commands today |
|
|
132
|
+
| `mme-recipe build` · `refresh` · `refresh-once` | `launch` tiers (extension) | ABSORB-LATER |
|
|
133
|
+
| `mme-recipe sidepanel [cycle\|open]` | `launch --sidepanel` (extension) | ABSORB-LATER |
|
|
134
|
+
|
|
135
|
+
#### `logs` — tail Metro/webpack + app logs · REAL (wave 3)
|
|
136
|
+
|
|
137
|
+
| | |
|
|
138
|
+
|---|---|
|
|
139
|
+
| **Human form** | `mm-harness logs` (compact, auto platform) |
|
|
140
|
+
| **Agent / advanced** | `mm-harness logs --full --platform mobile --json` |
|
|
141
|
+
|
|
142
|
+
| Today (real) | → mm-harness | Status |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| `mm-recipe logs` · `tail` · `logs --full` | `logs [--full]` | ABSORB-LATER · [ENV-GAP] `RECIPE_LOG_UI`/`RECIPE_LOG_EVENTS` → flags |
|
|
145
|
+
| `mme-recipe logs` · `tail` · `tail-webpack` | `logs` | ABSORB-LATER |
|
|
146
|
+
|
|
147
|
+
#### `debug` — open the debug console · REAL (wave 3)
|
|
148
|
+
|
|
149
|
+
| | |
|
|
150
|
+
|---|---|
|
|
151
|
+
| **Human form** | `mm-harness debug` (auto platform) |
|
|
152
|
+
| **Agent / advanced** | `mm-harness debug --worker` (extension SW) · `--dev-menu` · `--platform mobile` |
|
|
153
|
+
|
|
154
|
+
| Today (real) | → mm-harness | Status |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `mme-recipe debug` · `devtools` · `inspect` · `debug worker` | `debug [--worker]` | ABSORB-LATER |
|
|
157
|
+
| `mm-recipe debug` | `debug` | ABSORB-LATER |
|
|
158
|
+
| `mm-recipe dev-menu` · `devmenu` | `debug --dev-menu` (flag) | ABSORB-LATER · [DEFAULT-GAP] separate verb for one console concept |
|
|
159
|
+
|
|
160
|
+
#### `fixtures` — sync fixture files + set up the wallet · REAL (wave 3)
|
|
161
|
+
|
|
162
|
+
One canonical wallet fixture per checkout (SSOT). Fixture status is reported by `doctor` automatically (grounded: `fixtureSummary()` in `runner/src/doctor.ts`). `fixtures` group = `sync` and `set` only — no bare status verb.
|
|
163
|
+
|
|
164
|
+
Subcommands: `fixtures sync`, `fixtures set`.
|
|
165
|
+
|
|
166
|
+
| | |
|
|
167
|
+
|---|---|
|
|
168
|
+
| **Human form** | `mm-harness fixtures sync` · `mm-harness fixtures set` (applies THE canonical fixture — password read FROM the fixture, never typed; always prints "Want different accounts? Edit: <path>/wallet-fixture.json") |
|
|
169
|
+
| **Agent / advanced** | `mm-harness fixtures set --fixture <json> --platform mobile` (`--fixture` is agent-only; humans edit the canonical file directly) |
|
|
170
|
+
|
|
171
|
+
| Today (real) | → mm-harness | Status |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| `mm-recipe sync` · `mme-recipe sync` | `fixtures sync` | ABSORB-LATER |
|
|
174
|
+
| `mme-recipe update` · `sync-runtime` | `fixtures sync` | ABSORB-LATER |
|
|
175
|
+
| `mm-recipe setup-wallet` · `wallet-setup` | `fixtures set` | ABSORB-LATER · [ENV-GAP] `RECIPE_WALLET_FIXTURE` → `--fixture` (agent-only) |
|
|
176
|
+
| `mm-recipe setup:ios` · `setup:android` | `launch ios` **then** `fixtures set` | ABSORB-LATER |
|
|
177
|
+
| `mm-recipe unlock` | `fixtures set` (password from fixture) | ABSORB-LATER · [ENV-GAP] `MM_PASSWORD=… unlock` is the anti-pattern — read the fixture |
|
|
178
|
+
| Extension standalone wallet setup | `fixtures set` | **[GAP]** no standalone verb today — the first-run wallet is seeded by the legacy `mme-recipe up`; end-state home is `fixtures set` (launch / `launch --verify` never seed) |
|
|
179
|
+
|
|
180
|
+
### DISCOVER (agent composition layer — `--json` is PRIMARY)
|
|
181
|
+
|
|
182
|
+
The composition loop: `actions --json` → `call <action>` (try one via real engine path) → `flows --json` → compose `recipe.json` → `run --plan` (adapter-aware validate + plan, no device) → `run`.
|
|
183
|
+
|
|
184
|
+
`manifest` is **RETIRED**: raw protocol dump → `actions --raw`; validation → `run --plan` / `doctor`. `validate` verb **DISSOLVED** into `run` (`run` validates first; `run --plan` = plan-only; same or richer shape, plus adapter cross-check). **DISCOVER final shape: `actions` · `call` · `flows`** — no manifest verb, no validate verb. Shell completions are sourced from this same layer: `call` completes action names, `run`/`run --plan` complete flow refs, both with a per-checkout short-TTL cache.
|
|
185
|
+
|
|
186
|
+
#### `actions` · `call` · `flows` · ROUTES-NOW (call: REAL wave 2)
|
|
187
|
+
|
|
188
|
+
| | |
|
|
189
|
+
|---|---|
|
|
190
|
+
| **Human form** | `mm-harness actions --adapter mobile` · `mm-harness call unlock` · `mm-harness flows` |
|
|
191
|
+
| **Agent PRIMARY** | `mm-harness actions --adapter mobile --json` → `{ adapter, actions: [{ name, kind, description, fields, examples }] }` |
|
|
192
|
+
| | `mm-harness call metamask.perps.read_positions --arg symbol=BTC --adapter core --json` → `{ action, resolvedAction, args, trace, evidence, recovered, mutations, exitCode, schemaVersion }` (same shape as `run --json`, one-node subset) |
|
|
193
|
+
| | `mm-harness flows --json` → `{ sources, flows: [{ ref, source, file, description?, requiredParams?, shadows?, lastVerified? }] }` |
|
|
194
|
+
| **Plan before run** | `mm-harness run recipe.json --plan --json` → `{ plan[], validation: { status, findings }, schemaVersion }` (adapter-aware; exit 5 on errors) |
|
|
195
|
+
|
|
196
|
+
| Today (real) | → mm-harness | Status |
|
|
197
|
+
|---|---|---|
|
|
198
|
+
| `metamask-recipe actions --adapter …` | `mm-harness actions --adapter …` | ROUTES-NOW · [DEFAULT-GAP] `--adapter` required · [DISCOVERY-GAP] no `--action <name>` filter, no `--kind` filter, no keyword search |
|
|
199
|
+
| `metamask-recipe flows list\|promote` | `mm-harness flows [\|promote]` | ROUTES-NOW · `flows` = browse the reusable flow library (compose, don't rewrite); `promote` publishes a proven flow up a tier · bare `flows` = list · [DISCOVERY-GAP] no keyword filter, no per-flow body fetch, no platform filter |
|
|
200
|
+
| `mm-recipe`/`mme-recipe` `actions`/`doctor` (auto adapter) | same `mm-harness` verbs | ABSORB-LATER — porcelain supplies missing adapter default |
|
|
201
|
+
| hook layer `run-action app.unlock` | `mm-harness call unlock` (fuzzy: `unlock` → `metamask.wallet.unlock`) — **one-node recipe via real engine path** | REAL (wave 2) · ambiguous → exit 2 listing candidates |
|
|
202
|
+
| `mm-harness validate recipe.json` (old stub) | `mm-harness run recipe.json --plan` | **DISSOLVED** — stub teaching message updated to point at `run --plan`; `validate-command.ts` called internally by run engine (phase: `validate`) |
|
|
203
|
+
|
|
204
|
+
### PROVE
|
|
205
|
+
|
|
206
|
+
#### `run` — validate + execute a recipe, write evidence · ROUTES-NOW
|
|
207
|
+
|
|
208
|
+
**Validates first (adapter-aware):** before touching any device, `run` checks action existence, platform support, and fixture preconditions. Exit 5 on validation errors (same code for `run`, `run --plan`, `call`). `--plan` = plan-only: prints what would happen, touches NO device, exits 0/5. Phase state-machine: `resolve → install → healthcheck → recover → validate → launch → execute`. `--heal` defaults `infra-only`; healing never touches wallet state — only the explicit `fixtures set` mutates it.
|
|
209
|
+
|
|
210
|
+
| | |
|
|
211
|
+
|---|---|
|
|
212
|
+
| **Human form** | `mm-harness run recipe.json` (adapter + artifacts auto-defaulted) |
|
|
213
|
+
| **Plan before run** | `mm-harness run recipe.json --plan` (adapter-aware; no device; exit 0 = valid, exit 5 = errors) |
|
|
214
|
+
| **Agent / advanced** | `mm-harness run recipe.json --adapter mobile --project-root <repo> --artifacts-dir <dir> --record-video=full-run --heal=off --json --json-stream` |
|
|
215
|
+
|
|
216
|
+
| Today (real) | → mm-harness | Status |
|
|
217
|
+
|---|---|---|
|
|
218
|
+
| `metamask-recipe run … --adapter … --artifacts-dir …` | `mm-harness run …` | ROUTES-NOW · [DEFAULT-GAP] `--adapter` + `--artifacts-dir` mandatory today · [ENV-GAP] `RECIPE_LIBRARY_PATH` → `--library`/config |
|
|
219
|
+
| `mm-recipe run recipe.json` · `mme-recipe run recipe.json` (auto adapter+artifacts) | `mm-harness run recipe.json` | ABSORB-LATER — porcelain already supplies the good defaults the typed CLI lacks |
|
|
220
|
+
|
|
221
|
+
#### `doctor` · ROUTES-NOW
|
|
222
|
+
|
|
223
|
+
Pure read-only diagnostic. Absorbs the retired `manifest` verb's validation: readiness checks include manifest well-formedness + reports manifest path + protocol version. `--fix` mode runs healing without launching (same path as `launch`/`verify` self-healing but stops short of starting the app).
|
|
224
|
+
|
|
225
|
+
| | |
|
|
226
|
+
|---|---|
|
|
227
|
+
| **Human form** | `mm-harness doctor` |
|
|
228
|
+
| **Agent / advanced** | `mm-harness doctor --adapter mobile --target <repo> --json` |
|
|
229
|
+
| **Repair without launch** | `mm-harness doctor --fix [--json]` → `{ ..., "fixed": [...], "failed": [...] }` |
|
|
230
|
+
|
|
231
|
+
| Today (real) | → mm-harness | Status |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| `metamask-recipe doctor --adapter … --target …` | `mm-harness doctor` | ROUTES-NOW · [DEFAULT-GAP] `--adapter`+`--target` required |
|
|
234
|
+
| `mm-recipe`/`mme-recipe` `doctor` (auto adapter/target) | `mm-harness doctor` | ABSORB-LATER — porcelain supplies the missing defaults |
|
|
235
|
+
|
|
236
|
+
### RUNTIME OVERLAY
|
|
237
|
+
|
|
238
|
+
#### `install` · `verify` · `cleanup` · ROUTES-NOW
|
|
239
|
+
|
|
240
|
+
`live` is **REMOVED** — dissolved into `launch --verify` (same sequence: install overlay if missing → launch → CDP poll → smoke verify; zero capability lost — `launch --verify` never seeds fixtures).
|
|
241
|
+
|
|
242
|
+
| | |
|
|
243
|
+
|---|---|
|
|
244
|
+
| **Human form** | `mm-harness install` · `verify` · `cleanup` (platform auto-detected, target = cwd) |
|
|
245
|
+
| **`live` replacement** | `mm-harness launch [ios\|android] --verify` |
|
|
246
|
+
| **Agent / advanced** | `mm-harness verify --platform extension --target <repo> --json -- --cdp-port <port>` |
|
|
247
|
+
|
|
248
|
+
| Today (real) | → mm-harness | Status |
|
|
249
|
+
|---|---|---|
|
|
250
|
+
| `recipe-harness install\|verify\|cleanup\|live …` (skill) | `mm-harness install\|verify\|cleanup` · `live` → `launch --verify` | ROUTES-NOW; skill REMOVE |
|
|
251
|
+
| `metamask-recipe harness install\|verify\|cleanup\|live …` | `mm-harness install\|verify\|cleanup` (top-level) · `live` → `launch --verify` | ROUTES-NOW; `harness` prefix REMOVE |
|
|
252
|
+
| `mm-recipe prepare` · `mme-recipe prepare` | `install` / `launch` prep | ABSORB-LATER |
|
|
253
|
+
| `mme-recipe ready` · `ensure-ready` | `verify` (or advanced `ensure-ready`) | ABSORB-LATER |
|
|
254
|
+
|
|
255
|
+
### ADVANCED (agent / internal — rarely typed by hand)
|
|
256
|
+
|
|
257
|
+
| Today (real) | → mm-harness | Status |
|
|
258
|
+
|---|---|---|
|
|
259
|
+
| `metamask-recipe runtime-health` · `runtime-decision` · `runtime-launch` · `resolve-extension` · `ensure-ready` · `self-test` | logic moves INSIDE `launch`/`verify` self-healing path — no user-facing verb; `self-test` callable via `package.json` scripts only | KEEP-INTERNAL |
|
|
260
|
+
| `metamask-recipe manifest --adapter …` | **RETIRED** — (1) validation → `doctor` readiness check; (2) raw dump → `mm-harness actions --raw`; (3) path + protocol version → `doctor` explain-my-setup | REMOVE |
|
|
261
|
+
| `mm-recipe`/`mme-recipe` `runtime-status` · `decision` · `ports` · `status\|home\|health` · `stop` | operator/infra flags on `mm-harness` (e.g. `--json` status) | ABSORB-LATER |
|
|
262
|
+
| `mm-recipe`/`mme-recipe` `completion\|complete` | bundled `mm-harness` completions (dynamic from DISCOVER layer) | KEEP-INTERNAL / REMOVE (old `_recipe`) |
|
|
263
|
+
| `mm-recipe`/`mme-recipe` `interactive\|menu` | interactive shell | ABSORB-LATER |
|
|
264
|
+
| `mm-recipe` bridge verbs: `app-status` · `route` · `navigate` · `back` · `accounts` · `select-account` · `screenshot` | recipe-driven or future flags | ABSORB-LATER |
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Decisions (final)
|
|
269
|
+
|
|
270
|
+
The surface below is settled — the design passed a three-round external review (final verdict: SOUND). The rulings that shape day-to-day use:
|
|
271
|
+
|
|
272
|
+
- **One bin, clean break.** `mm-harness` is the only command; `metamask-recipe` / `mm-recipe` / `mme-recipe` and the `harness <verb>` form are removed in the coordinated caller-sweep wave (CLI-SPEC.md Part 3).
|
|
273
|
+
- **DISCOVER = `actions · call · flows`.** `manifest` is retired (raw dump → `actions --raw`; validation → `run --plan` / `doctor`; path + protocol version → `doctor`). `validate` is dissolved into `run` (`run` always validates first; `run --plan` = plan-only, no device).
|
|
274
|
+
- **`call` is a one-node recipe** through the real engine path — same trace / evidence / `--json` shape as `run`; one execution path, two doors. `call` inherits `run` semantics in full (default `--heal=infra-only`).
|
|
275
|
+
- **`live` is dissolved into `launch --verify`** (install overlay → launch → CDP poll → smoke verify; zero capability lost — `launch --verify` never seeds fixtures). No `live` verb on any surface.
|
|
276
|
+
- **`--heal` = `off | infra-only | auto`** (+ `--yes` for non-interactive confirmation). `launch` defaults `auto`; `run` and `call` default `infra-only`; `off` is repro-preserving and also disables auto-install. Recovery bounds are ALWAYS enforced (recipe running / app-logic failure / same recovery already failed once → `recoverable:false`); no flag bypasses them. `--heal=off` is the single opt-out (it also disables auto-install).
|
|
277
|
+
- **Wallet state is mutated ONLY by the explicit `fixtures set`.** Healing never touches wallet state — overlay / Metro / Chrome recovery is infra; wallet data is not. If recovery would require a wallet write, the verb stops with `recoverable:false` and `userAction: "run mm-harness fixtures set"`. `fixtures` is wallet DATA only and never touches the overlay.
|
|
278
|
+
- **Overlay install notice** (not a "consent print"): stderr-only in human mode; in `--json` it appears solely as `mutations[]`, so stdout stays clean for machines.
|
|
279
|
+
- **Exit code 5 = validation failure everywhere** (`run`, `run --plan`, `call`) — no mode-specific meanings. `run --plan` items carry `confidence: static | conditional` so a plan never claims live runtime facts. Full taxonomy + agent error contract: CLI-SPEC.md Part 5.
|
|
280
|
+
- **Agent error contract:** structured `error:{code,message,cause,retryable,userAction}`, stable `recovered[]` / `mutations[]`, a phase state-machine, JSONL `--json-stream`, and `recoverable:false` + `attemptedRecoveries[]` to stop retry loops (CLI-SPEC.md Part 5).
|
|
281
|
+
- **Quick-launch change detection:** before a quick launch (no `--build`), `launch` checks native/webpack build inputs; if changed → teaching error pointing at `--build`. Never runs on a stale build.
|
|
282
|
+
- **Daily verbs auto-ensure the overlay**; humans never run `install`. `install` / `verify` / `cleanup` are the explicit top-level forms for CI/agents.
|
|
283
|
+
- **`flows` bare = list**; `flows promote` is the explicit subcommand.
|
|
284
|
+
- **Implementation:** `commander` (the library `@farmslot/recipe-harness` already uses) + bundled dynamic zsh/bash completions sourced from the DISCOVER layer.
|
|
285
|
+
|
|
286
|
+
**Deferred to later waves (sequencing, not open questions):** the `[DEFAULT-GAP]` auto-defaults (adapter/artifacts for `run` / `doctor` / `actions`), the `[ENV-GAP]` env→flag moves (CLI-SPEC.md Part 4), the caller sweep that deletes the old names (Part 3), and the repo rename.
|
|
287
|
+
|
|
288
|
+
### Considered and rejected
|
|
289
|
+
|
|
290
|
+
- **Teaching-tombstone stub bins** (`mm-harness-legacy`, etc.): Rejected. Pre-adoption burden with zero payoff; the coordinated wave (CLI-SPEC.md Part 3) updates all callers atomically. No tombstone bins needed.
|
|
291
|
+
|
|
292
|
+
## How farmslot calls mm-harness (preflight & the fleet binding)
|
|
293
|
+
|
|
294
|
+
"Preflight" survives as a capability, not an exposed concept: it is what `launch` does before returning (readiness: Metro/bundle → app → health/bridge poll), with `launch --verify` as the prove-it tier and `doctor` as the read-only view. The fleet is just another agent-grade caller — farmslot prepare profiles keep their git / fixtures / deps phases, and the preflight/health hooks collapse to one call: `mm-harness launch <target> --verify --heal=auto --json`. Same-capability by construction: the machine contract (`--json` schemas, `--heal`, exit-code taxonomy, `recovered[]` / `mutations[]` / `recoverable:false`) is the one agents already use. Three bindings, one verb: the engineer types `mm-harness launch ios`; the slot's prepare hook calls the same verb with slot context; dispatch scales it across the fleet. (Full contract: CLI-SPEC.md Part 6.)
|
|
295
|
+
|