@deeeed/metamask-harness 0.17.4 → 0.18.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +775 -0
  2. package/README.md +65 -71
  3. package/adapters/extension/ensure-browser.sh +12 -1
  4. package/adapters/extension/inject.mjs +7 -0
  5. package/adapters/extension/launch-browser.cjs +10 -3
  6. package/adapters/extension/lib/chrome-args.cjs +31 -0
  7. package/adapters/extension/lib/macos-focus.cjs +32 -0
  8. package/adapters/extension/live.sh +10 -20
  9. package/adapters/manifest.json +8 -0
  10. package/adapters/mobile/open-device.sh +45 -7
  11. package/adapters/mobile/verify.sh +15 -3
  12. package/adapters/shared/harness-source-fingerprint.mjs +49 -0
  13. package/adapters/shared/install-repo-deps.sh +1 -5
  14. package/adapters/shared/open-debug.mjs +184 -103
  15. package/adapters/shared/resolve-slot-ports-core.mjs +23 -6
  16. package/adapters/shared/resolve-slot-ports.sh +22 -5
  17. package/bin/mm-harness +15 -3
  18. package/dist/adapters/core/surface.js +4 -1
  19. package/dist/adapters/extension/console-capture.js +3 -1
  20. package/dist/adapters/extension/harness-freshness.js +39 -0
  21. package/dist/adapters/extension/product-config.js +110 -0
  22. package/dist/adapters/extension/runtime-decision.js +20 -71
  23. package/dist/adapters/extension/surface.js +19 -1
  24. package/dist/adapters/mobile/prepare.js +17 -0
  25. package/dist/adapters/mobile/source-freshness.js +26 -41
  26. package/dist/adapters/mobile/surface.js +4 -1
  27. package/dist/adapters/resolve-slot-ports.js +2 -0
  28. package/dist/adapters/slot-ports.js +13 -32
  29. package/dist/adapters.js +50 -17
  30. package/dist/checkout-lock.js +27 -2
  31. package/dist/cli-color.js +19 -0
  32. package/dist/cli-commands.js +1 -1
  33. package/dist/cli.js +2 -3
  34. package/dist/command-contract.js +13 -3
  35. package/dist/commands/call.js +115 -29
  36. package/dist/commands/checklist.js +4 -1
  37. package/dist/commands/completion-candidates.js +20 -13
  38. package/dist/commands/debug.js +31 -38
  39. package/dist/commands/doctor.js +33 -6
  40. package/dist/commands/fixtures.js +65 -17
  41. package/dist/commands/flows.js +39 -10
  42. package/dist/commands/launch/extension.js +40 -15
  43. package/dist/commands/launch/index.js +41 -5
  44. package/dist/commands/list-executables.js +151 -29
  45. package/dist/commands/manifest.js +127 -18
  46. package/dist/commands/parse-args.js +11 -1
  47. package/dist/commands/run-engine.js +384 -56
  48. package/dist/commands/run.js +112 -17
  49. package/dist/commands/shared.js +22 -2
  50. package/dist/commands/status-probe.js +3 -0
  51. package/dist/commands/status.js +1 -0
  52. package/dist/completions-cache.js +1 -1
  53. package/dist/doctor.js +56 -6
  54. package/dist/harness.js +6 -5
  55. package/dist/heal-bounds.js +1 -1
  56. package/dist/live-adapter-contract.js +132 -12
  57. package/dist/manifest.js +161 -1
  58. package/dist/mm-harness-cli.js +13 -7
  59. package/dist/recipe-security.js +178 -0
  60. package/dist/runner.js +87 -13
  61. package/dist/runtime-context.js +8 -26
  62. package/docs/CONTRIBUTING.md +137 -0
  63. package/docs/QA.md +185 -0
  64. package/docs/RECIPES.md +161 -0
  65. package/docs/SECURITY.md +88 -0
  66. package/library/actions/core/perps/read_account.mjs +2 -2
  67. package/library/actions/core/perps/read_orders.mjs +2 -1
  68. package/library/actions/core/perps/read_positions.mjs +2 -1
  69. package/library/actions/core/wallet/list_accounts.mjs +95 -0
  70. package/library/actions/extension/platform/cdp.mjs +1 -0
  71. package/library/actions/extension/wallet/list_accounts.mjs +41 -0
  72. package/library/actions/mobile/platform/bridge.mjs +1 -5
  73. package/library/actions/mobile/wallet/list_accounts.mjs +37 -0
  74. package/library/manifests/core.action-manifest.json +61 -0
  75. package/library/manifests/extension.action-manifest.json +53 -0
  76. package/library/manifests/mobile.action-manifest.json +53 -0
  77. package/library/recipes/runner/action-validation.extension.recipe.json +8 -1
  78. package/library/recipes/runner/action-validation.mobile.recipe.json +8 -1
  79. package/package.json +10 -6
  80. package/scripts/completions.sh +7 -7
  81. package/docs/ADAPTER-SURFACE.md +0 -26
  82. package/docs/CHEATSHEET.md +0 -48
  83. package/docs/CLI-ERGONOMICS-AUDIT.md +0 -32
  84. package/docs/CLI-ERGONOMICS-HUMAN-QA.md +0 -64
  85. package/docs/CODE-MAP.md +0 -62
  86. package/docs/UX-PRINCIPLES.md +0 -66
  87. package/docs/VIDEO-DEMO-VALIDATION.md +0 -74
  88. package/docs/architecture.md +0 -88
  89. package/docs/live-adapter-contract.md +0 -190
  90. package/docs/package-boundaries.md +0 -47
  91. package/docs/perps-flow-catalog.md +0 -235
  92. package/docs/recipe-libraries.md +0 -71
  93. package/docs/runtime-file-conventions.md +0 -36
@@ -1,32 +0,0 @@
1
- <!-- Generated by scripts/generate-cli-ergonomics-audit.mjs. Do not edit by hand. -->
2
- # CLI ergonomics audit
3
-
4
- This matrix tracks the public command surface. “Covered” means the shared preflight contract and
5
- `tests/contract/cli-teaching-errors.test.sh` exercise the behavior without dispatching runtime work.
6
- Runtime recovery is claimed only where command-specific failures return a stable `userAction`.
7
- Success hints are intentionally limited to lifecycle transitions with one truthful next command;
8
- discovery, read-only, and terminal evidence commands do not invent one. ID prefix support is N/A
9
- unless a command displays a shortened ID that another command accepts.
10
-
11
- | Command | Bad flag | First feedback | `--json` recovery | Success next step | Displayed ID prefix |
12
- |---|---|---|---|---|---|
13
- | `status` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | structured `next` | N/A: command displays no shortened ID |
14
- | `checklist` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage errors covered; no runtime recovery claim | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
15
- | `actions` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
16
- | `stop` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | launch `next` when the adapter has one unambiguous launch | N/A: command displays no shortened ID |
17
- | `call` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
18
- | `flows` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage errors covered; no runtime recovery claim | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
19
- | `run` | covered: `CLI_UNKNOWN_OPTION` | TTY intent before slow work; machine output clean | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
20
- | `last` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
21
- | `doctor` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
22
- | `check` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
23
- | `recipe-quality` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
24
- | `provision` | covered: `CLI_UNKNOWN_OPTION` | TTY intent before slow work; machine output clean | usage + runtime `error.code/message/userAction` | launch `next` after install | N/A: command displays no shortened ID |
25
- | `install` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | verify `next` | N/A: command displays no shortened ID |
26
- | `verify` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | status `next` | N/A: command displays no shortened ID |
27
- | `cleanup` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | install `next` | N/A: command displays no shortened ID |
28
- | `launch` | covered: `CLI_UNKNOWN_OPTION` | TTY intent before slow work; machine output clean | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
29
- | `logs` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
30
- | `debug` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage errors covered; no runtime recovery claim | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
31
- | `update` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
32
- | `fixtures` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
@@ -1,64 +0,0 @@
1
- # Human QA
2
-
3
- Run this from each product checkout before a release. Verify the visible outcome,
4
- not only the exit code.
5
-
6
- Run the non-visual gate first:
7
-
8
- ```bash
9
- yarn qa:human \
10
- --extension /path/to/metamask-extension \
11
- --mobile /path/to/metamask-mobile \
12
- --core /path/to/metamask-core \
13
- --artifacts-dir temp/human-qa
14
- ```
15
-
16
- It verifies live readiness, installed runtime, debugger target resolution, smoke
17
- evidence, and unchanged tracked product source. The checks below cover outcomes
18
- that still require eyes or an intentional source edit.
19
-
20
- ## Common
21
-
22
- - [ ] `mm-harness --version` prints the candidate version.
23
- - [ ] `mm-harness doctor` detects the correct product and reports only current
24
- configuration.
25
- - [ ] Without `capture-helper`, `doctor` names the CDP or simulator/ADB screenshot
26
- fallback and says video is unavailable.
27
- - [ ] A misspelled flag explains the error and gives a runnable next command.
28
- - [ ] `mm-harness actions` and `mm-harness flows` return useful, bounded discovery.
29
- - [ ] `mm-harness fixtures set` either applies the fixture or names the missing
30
- file and exact recovery action.
31
- - [ ] `mm-harness run <safe-recipe> --artifacts-dir temp/qa-proof` prints findings,
32
- diagnostics, and absolute evidence paths.
33
- - [ ] `mm-harness last --json` identifies that run without rerunning it.
34
- - [ ] `mm-harness doctor --json` is one parseable document with no human decoration.
35
-
36
- ## Extension
37
-
38
- - [ ] `mm-harness launch` opens/reuses the checkout's named Chrome profile.
39
- - [ ] `mm-harness launch --sidepanel` opens the MetaMask sidepanel without extra
40
- Extension tabs.
41
- - [ ] `mm-harness debug` opens connected DevTools for the active MetaMask target.
42
- - [ ] `mm-harness logs --source extension` shows Extension console events.
43
- - [ ] `mm-harness logs --source dapp` shows dapp console events separately.
44
- - [ ] Edit a visible source string twice, waiting for successful incremental
45
- compilation after each edit; refresh the browser and confirm both changes.
46
- - [ ] Revert the edit, confirm a third incremental compilation, and verify the
47
- same watcher and Chrome process were reused.
48
-
49
- ## Mobile
50
-
51
- - [ ] `mm-harness launch ios` boots/reuses the intended simulator and opens the app.
52
- - [ ] `mm-harness launch android` targets the intended emulator/device.
53
- - [ ] `mm-harness logs --source metro` and `--source app` show distinct streams.
54
- - [ ] `mm-harness debug` opens the usable React Native developer surface.
55
- - [ ] Change a visible JS string, confirm Metro rebuilds, reload the app, and see
56
- the change without a native rebuild.
57
-
58
- ## Core
59
-
60
- - [ ] `mm-harness status`, `doctor`, `actions`, `flows`, and a safe recipe run work
61
- without browser/device assumptions.
62
-
63
- Record the command, version, checkout SHA, visible mismatch, exit code, and JSON
64
- error envelope for any failure.
package/docs/CODE-MAP.md DELETED
@@ -1,62 +0,0 @@
1
- # Code map — where things live and how a command flows
2
-
3
- One page for humans. The contracts live in docs/UX-PRINCIPLES.md and
4
- docs/ADAPTER-SURFACE.md; this is the geography.
5
-
6
- ## How a command flows
7
-
8
- ```
9
- bin/mm-harness bash front door: MM_HARNESS_BIN dev/prod switch,
10
- │ dist-vs-src selection (dist wins when present;
11
- │ stale-dist warning), deps ensure
12
-
13
- src/mm-harness-cli.ts commander surface: grouped colored help, per-command
14
- │ --help and usage errors; delegates in-process
15
-
16
- src/cli.ts parse + dispatch ONLY — no verb logic lives here
17
-
18
- ├── src/commands/<verb>.ts one module per verb (doctor, stop, call, run,
19
- │ │ provision, fixtures, flows, logs, debug, …)
20
- │ ▼
21
- │ src/adapters/surface.ts AdapterSurface registry — per-platform behavior
22
- │ │ (ports, runtime status, dev server, log sources)
23
- │ ▼
24
- │ src/adapters/{mobile,extension,core}/ TS logic per platform
25
-
26
- └── src/harness.ts overlay lifecycle (install/verify/cleanup) — writes
27
- │ the per-checkout overlay + runner delegate
28
-
29
- adapters/ SHELL LEAVES (repo root — not src/adapters!):
30
- mobile/ extension/ single-OS-op scripts the TS layer spawns
31
- core/ shared/ (simctl/adb/tmux/metro/webpack lifecycle)
32
- ```
33
-
34
- ## The two `adapters/` directories
35
-
36
- - `adapters/` (repo root) — executable shell leaves. Thin, OS-facing, spawned by TS.
37
- - `src/adapters/` — TypeScript platform logic behind the AdapterSurface.
38
- Rule: logic/decisions in TS; a leaf only executes. A leaf converts to TS only when
39
- it starts making decisions (see backlog ruling), never as a campaign.
40
-
41
- ## Other roots
42
-
43
- - `library/` — recipe library: actions (`library/actions/<adapter>/…`, executable
44
- action modules — importing one RUNS it, see library/README.md), flows, recipes.
45
- - `tests/contract/` — hermetic bash contract tests (PATH-stubbed OS tools). The
46
- launch-leaf-flags test enforces composer↔leaf flag agreement.
47
- - `dist/` — esbuild output; the ONLY thing published runs. gitignored; in a source
48
- checkout it SHADOWS src when present (bin warns when it goes stale).
49
- - Per-checkout runtime state lives in the TARGET repo: `temp/recipe/runtime/`
50
- (context, logs, wallet fixture) and `temp/recipe/harness/<adapter>/` (overlay +
51
- runner delegate pinned to the installing bin via `.runner-source`).
52
-
53
- ## Adding things
54
-
55
- - **A verb**: module in `src/commands/`, register in `src/cli.ts` dispatch + the
56
- commander metadata in `src/mm-harness-cli.ts` (help group), contract test.
57
- - **A flag**: parse in the verb module; if it reaches a leaf, the leaf's parser
58
- must accept it (launch-leaf-flags test will fail otherwise) — or pass via env.
59
- - **A leaf**: shell under `adapters/<platform>/`, spawned via the shared spawn
60
- helpers (never raw exec), contract test with PATH stubs, errors teach escape.
61
- - **A platform behavior**: extend the AdapterSurface, implement per platform —
62
- verbs must not branch on adapter for surface-owned behavior.
@@ -1,66 +0,0 @@
1
- # UX principles — the mm-harness interaction contract
2
-
3
- Every command surface follows these rules. They are review criteria, not aspirations:
4
- a PR that adds a command or output path is checked against each one.
5
-
6
- **Scope: the HUMAN surface.** The agent contract is exempt and inviolable: under
7
- `--json`, stdout carries exactly one machine-readable envelope — no color, no
8
- banners, no decorative lines. Progress/streaming exists
9
- for agents too, but only ever on stderr. When a rule below conflicts with envelope
10
- purity, the envelope wins.
11
-
12
- ## 1. Context-aware by default
13
- The CLI answers relative to the checkout it is standing in.
14
- - Adapter is auto-detected everywhere (`--adapter` overrides; a bare command never
15
- fails on a value detection can supply).
16
- - The slot context the orchestrator wrote into the checkout
17
- (`<runtime_dir>/agentic-runtime.json`) is the authoritative source for device,
18
- ports, and slot identity — naming formulas are last-resort fallbacks and never
19
- hardcode pool prefixes (they go stale on rename).
20
- - Output is scoped to the platform: an extension-only field is noise on a mobile
21
- slot; help, flag lists, and completion candidates shrink to what applies here.
22
- - Enforcement: platform-specific behavior is resolved through the adapter surface
23
- (`getAdapterSurface(adapter)`), never a per-command `if (adapter === …)` ladder —
24
- that ladder is how commands go platform-blind. See docs/ADAPTER-SURFACE.md.
25
-
26
- ## 2. Never silent, never opaque
27
- Long operations show intent immediately and progress continuously.
28
- - First line within milliseconds: what is being done, where (device/port), and
29
- where the full log lives.
30
- - Add an explicit first line only when work can block before existing output. Fast
31
- commands use their result as acknowledgement; they do not print a redundant banner.
32
- - Leaf output streams live to stderr — `--json` reserves stdout for the envelope,
33
- it never buys silence. Quiet stretches get heartbeats with elapsed time.
34
- - Each dev server a command starts gets its tmux log-tail window at launch time
35
- (window creation is launch-coupled; users re-create separately when they close one).
36
-
37
- ## 3. Summaries state outcomes
38
- The final line says what actually happened: target device, what the tier meant,
39
- resulting state — never a bare status word. Dev-override runs are marked
40
- (`[dev: MM_HARNESS_BIN]`) so it is always evident which bin served.
41
-
42
- ## 4. Dev and prod are explicit
43
- The global install is prod (`mm-harness`); a dev checkout runs via the documented
44
- `MM_HARNESS_BIN` switch (conventionally aliased `mmdev-harness`). The dev override
45
- announces itself in help and summaries. Completions cover both names.
46
-
47
- ## 5. Errors teach the exact escape
48
- Every failure states the next command for the caller's actual situation. A wrong
49
- hint (an escape for a different failure mode) is a bug of the same severity as
50
- the failure itself.
51
-
52
- ## 6. Lifecycle verbs are symmetric and idempotent
53
- What a command starts, a sibling verb stops (`launch`/`stop`), scoped to what this
54
- checkout owns (port-scoped, session-scoped) — never "whatever is running".
55
- Nothing-to-do is success. Tests never leak into the operator's real tmux.
56
-
57
- ## 7. Color is consistent and optional
58
- All human output styles through `cli-color.ts` (headers, ok/warn/err states,
59
- provenance, "Next:" hints); `NO_COLOR`/non-TTY degrade to plain text. No surface
60
- invents its own ANSI.
61
-
62
- ## 8. Doctor is the status surface
63
- `doctor` reports, per platform: live runtime state (deps currency, dev-server
64
- up/stale on the slot's resolved port, app/browser presence), the scoped runtime
65
- context with provenance (`[file]`/`[env]`/`[default]`), and the exact customize
66
- hint per row. Read-only unless `--fix`.
@@ -1,74 +0,0 @@
1
- # Video demo validation
2
-
3
- Use this checklist against the installed release before recording. Each checkout
4
- auto-detects its platform, ports, and slot; the paths below are placeholders only.
5
-
6
- ```bash
7
- export EXTENSION_CHECKOUT=/path/to/metamask-extension
8
- export MOBILE_CHECKOUT=/path/to/metamask-mobile
9
- export CORE_CHECKOUT=/path/to/core
10
- ```
11
-
12
- ## Common
13
-
14
- - [ ] `mm-harness --version` prints the intended release.
15
- - [ ] `mm-harness doctor` explains any unavailable capability and gives one next step.
16
- - [ ] Recipe results print diagnostics and absolute artifact paths inline.
17
- - [ ] `git status --short` is unchanged in each product checkout after validation.
18
-
19
- ## Extension
20
-
21
- ```bash
22
- cd "$EXTENSION_CHECKOUT"
23
- mm-harness launch --build --verify
24
- mm-harness doctor
25
- mm-harness actions positions
26
- mm-harness flows
27
- mm-harness run runner.smoke --artifacts-dir temp/demo
28
- mm-harness run wallet.smoke --artifacts-dir temp/wallet-demo
29
- mm-harness logs --source app
30
- mm-harness debug
31
- ```
32
-
33
- - [ ] Launch keeps an incremental webpack watcher alive.
34
- - [ ] Two small source edits compile incrementally; browser refresh shows both changes.
35
- - [ ] `debug` connects to the active slot's MetaMask target and opens Console.
36
- - [ ] `logs --source app` shows extension logs; `--source dapp` and `--source webpack`
37
- show their separate streams.
38
- - [ ] Each recipe prints `diagnostics: CLEAN` or expands every warning/error inline.
39
- - [ ] Each recipe prints absolute paths for its report, trace, diagnostics, screenshots,
40
- and artifact manifest.
41
-
42
- ## Mobile
43
-
44
- ```bash
45
- cd "$MOBILE_CHECKOUT"
46
- mm-harness launch ios --verify
47
- mm-harness fixtures set
48
- mm-harness call metamask.wallet.ensure_unlocked
49
- mm-harness status
50
- mm-harness logs --source app
51
- ```
52
-
53
- - [ ] The intended simulator is running; focus changes only when explicitly requested.
54
- - [ ] Fixture setup reads the canonical checkout fixture and unlocks the wallet.
55
- - [ ] Status reports the live route, wallet state, account, and fixture readiness.
56
- - [ ] App logs are separate from Metro logs (`mm-harness logs --source metro`).
57
-
58
- ## Core
59
-
60
- ```bash
61
- cd "$CORE_CHECKOUT"
62
- mm-harness doctor
63
- mm-harness run runner.smoke --artifacts-dir temp/demo
64
- ```
65
-
66
- - [ ] Doctor reports the headless controller ready.
67
- - [ ] The canonical wallet fixture supplies the default account.
68
- - [ ] Evidence paths are absolute; diagnostics is explicitly `N/A` for headless Core.
69
-
70
- ## Recording path
71
-
72
- Show the Extension discovery and proof commands, then the equivalent Mobile and Core
73
- commands. The useful story is: one auto-detected CLI, reusable team libraries,
74
- parameterized recipes, app diagnostics, and proof artifacts that a human can inspect.
@@ -1,88 +0,0 @@
1
- # Architecture
2
-
3
- `mm-harness` is the MetaMask adapter and CLI over the generic Recipe Protocol
4
- engine. Control flows downward only:
5
-
6
- ```text
7
- bin/mm-harness
8
- → src/ typed CLI, decisions, orchestration, evidence
9
- → @farmslot/recipe-harness generic graph execution and transports
10
- → @farmslot/protocol recipe, manifest, trace, artifact schemas
11
- → adapters/ focused OS, browser, simulator, and device leaves
12
- → library/ MetaMask actions, flows, recipes, manifests
13
- → MetaMask checkout app under test
14
- ```
15
-
16
- Nothing under `adapters/` or `library/` calls back into `mm-harness`. TypeScript
17
- owns sequencing; a leaf performs one platform operation and exits; the library
18
- defines composable behavior.
19
-
20
- ## Ownership
21
-
22
- | Layer | Owns | Does not own |
23
- |---|---|---|
24
- | `@farmslot/protocol` | Recipe and evidence schemas | execution or product behavior |
25
- | `@farmslot/recipe-harness` | graph execution, generic `ui.*`, traces and artifacts | MetaMask behavior |
26
- | this package | MetaMask actions, runtime control, CLI, diagnostics | task acceptance criteria or copied engine logic |
27
- | skills/checklists | task workflow and proof expectations | runtime or runner implementation |
28
- | product checkout | application and explicit debug hooks | harness scripts or private workflow logic |
29
-
30
- A capability reusable without MetaMask belongs in the generic engine. A durable
31
- MetaMask operation belongs here. Ticket-specific assertions stay in the task's
32
- recipe or checklist.
33
-
34
- ## Repository layout
35
-
36
- | Path | Responsibility |
37
- |---|---|
38
- | `bin/mm-harness` | one public executable |
39
- | `src/commands/` | public command behavior |
40
- | `src/adapters/` | typed product decisions and orchestration |
41
- | `adapters/<platform>/` | focused shell/Node runtime leaves |
42
- | `adapters/shared/` | cross-platform OS glue |
43
- | `adapters/*/overlay/` | the only files installed or patched into a checkout |
44
- | `library/actions/` | executable MetaMask action adapters |
45
- | `library/flows/` | reusable parameterized behavior |
46
- | `library/recipes/` | reusable proof recipes |
47
- | `library/manifests/` | declared capability surface |
48
- | `scripts/` | repository development checks only |
49
-
50
- All TypeScript belongs under `src/`. New standalone runtime helpers use ESM
51
- unless their host runtime requires CommonJS. Shell remains limited to operations
52
- that genuinely need shell/device tools.
53
-
54
- ## Runtime isolation
55
-
56
- Each checkout owns its runtime state:
57
-
58
- ```text
59
- temp/recipe/runtime/ ports, processes, fixture, logs, runtime identity
60
- temp/recipe/harness/ installed runtime overlay
61
- ```
62
-
63
- Defaults live in `adapters/shared/path-defaults.json`. Every browser profile,
64
- simulator/device selection, port, watcher, and evidence directory must resolve
65
- from the current checkout so parallel slots do not share state.
66
-
67
- Extension uses an isolated Chrome profile and CDP port. Its normal watcher builds
68
- to product `dist/chrome`, then synchronizes successful output into the isolated
69
- runtime extension. Mobile owns an isolated Metro/device identity. Core remains
70
- headless.
71
-
72
- ## Proof boundary
73
-
74
- `launch` prepares the runtime. `run` validates and executes a recipe through the
75
- generic engine. Runtime setup may seed declared fixtures before proof begins;
76
- proof actions must not mutate hidden product state to fabricate a result.
77
-
78
- Each run produces a summary, trace, diagnostics where applicable, and an artifact
79
- manifest. Application warnings/errors are side findings unless a recipe assertion
80
- turns them into a proof failure.
81
-
82
- ## Change checks
83
-
84
- - Put the change in the owning layer; do not duplicate behavior in a skill or leaf.
85
- - Keep actions parameterized and manifests honest.
86
- - Validate the machine contract and the visible human outcome.
87
- - Exercise affected platforms on real checkouts when runtime behavior changes.
88
- - Run `yarn check` and update `CHANGELOG.md` for user-visible changes.
@@ -1,190 +0,0 @@
1
- # Live Adapter Contract
2
-
3
- The MetaMask runner implements Recipe Protocol v1 through the shared recipe
4
- harness package. Project-specific live behavior is supplied by
5
- manifest-declared action adapters.
6
-
7
- Official `ui.*` semantics are implemented by
8
- `createStandardUiAdapters({ transport })` plus shared CDP/React Native base
9
- transports. The MetaMask runner supplies only tiny runtime bindings that point
10
- those base transports at the Extension CDP page or Mobile React Native bridge.
11
- MetaMask-specific actions remain separate manifest-declared live adapters.
12
-
13
- For actions that must prove real product behavior, especially `metamask.perps.*`, static placeholders are refused by default. A live adapter script must exist in one of these locations. Domain-grouped paths are preferred so code ownership stays obvious:
14
-
15
- ```text
16
- $METAMASK_RECIPE_LIVE_ADAPTER_DIR/<platform>/<domain>/<action-local-name>.mjs
17
- $METAMASK_RECIPE_LIVE_ADAPTER_DIR/shared/<domain>/<action-local-name>.mjs
18
- <runner>/library/actions/<platform>/<domain>/<action-local-name>.mjs
19
- <runner>/library/actions/shared/<domain>/<action-local-name>.mjs
20
- ```
21
-
22
- Action adapters are grouped `.mjs` modules. Flat files, CommonJS, and shell
23
- adapters are not part of the contract. Do not add `ui.*` files here; official UI
24
- actions go through shared base transports. Examples:
25
-
26
- ```text
27
- library/actions/extension/perps/ensure_positions.mjs
28
- library/actions/extension/perps/close_positions.mjs
29
- library/actions/extension/perps/close_orders.mjs
30
- library/actions/mobile/perps/place_order.mjs
31
- library/actions/mobile/wallet/ensure_unlocked.mjs
32
- ```
33
-
34
- The runner invokes the script with one argument: a JSON input file path. The same path is also available as `METAMASK_RECIPE_ADAPTER_INPUT`. The script must write JSON to `outputPath` from the input document, or print JSON to stdout.
35
-
36
- Input shape:
37
-
38
- ```json
39
- {
40
- "schemaVersion": 1,
41
- "platform": "mobile|extension",
42
- "action": "metamask.perps.ensure_positions",
43
- "node": {},
44
- "context": {
45
- "nodeId": "ensure-clean",
46
- "projectRoot": "/path/to/product",
47
- "artifactsDir": "/path/to/artifacts"
48
- },
49
- "outputPath": "/tmp/.../output.json"
50
- }
51
- ```
52
-
53
- Output shape is action-specific, but must be redacted and suitable for `trace.json`. If the adapter captures evidence files, write them under `context.artifactsDir` and return relative artifact paths for the runner adapter to index in a follow-up implementation.
54
-
55
- Proof rule: live adapters must drive real supported app/API paths. They must not write directly into UI state, DOM state, React/Redux/MobX state, local storage, controller internals, or any mid-recipe state that fabricates the proof condition.
56
-
57
- ## Controller/API calls vs visible UI proof
58
-
59
- Recipe authors should choose the layer based on what must be proven:
60
-
61
- | Need | Use | Rule |
62
- |---|---|---|
63
- | Fast reproducible setup/teardown before or after the proof window | `metamask.*` domain actions such as `start_state`, `ensure_positions`, `close_orders` | May use supported product/controller APIs, but must read/assert the final state. |
64
- | Read-only state proof | `metamask.*.read_*` or `metamask.*.assert_*` | Must return redacted live state in trace output. |
65
- | Human-visible acceptance criterion | official `ui.*` actions | Drive the actual visible path: press/tap, input/keypad, scroll into view, screenshot. Do not replace it with a controller call. |
66
- | Ticket-specific visual detail | task-local recipe assertions/evidence | Do not add a reusable action only for one ticket. |
67
-
68
- ## Shared action-surface boundaries
69
-
70
- The manifest is a durable capability contract, not a place to encode one
71
- ticket's acceptance criteria. Do not add shared `metamask.*` actions for ticket
72
- IDs, POCs, exact test IDs, exact copy, styling, placement, or other one-off UI
73
- proof needs.
74
-
75
- Use:
76
-
77
- - official `ui.*` actions for reusable presence, input, scroll, and screenshot
78
- behavior;
79
- - screenshot `claims` for visual, copy, and layout proof;
80
- - task-local composed flows under the task artifact directory when a ticket
81
- needs a reusable helper for that ticket only;
82
- - safe direct CDP/controller calls for read/assert or supported setup paths,
83
- never state fabrication.
84
-
85
- Add or keep a shared action only when it represents a durable parameterized
86
- domain capability useful across many tasks, such as `metamask.perps.start_state`,
87
- `metamask.perps.place_order`, `metamask.perps.close_positions`, or
88
- `metamask.perps.assert_positions`.
89
-
90
- `ui.scroll` is part of the current executable contract and runner.action-validation must
91
- prove both normal scrolling and `scroll_into_view` before screenshot capture.
92
- `ui.gesture` is intentionally not advertised yet; drag/swipe proof must wait
93
- until the shared runtime and this runner expose and validate that action on both
94
- platforms.
95
-
96
-
97
-
98
- ## Flow catalog follow-up
99
-
100
- Action adapters fulfill one manifest-declared operation. Production recipes should also be able to call domain flow catalogs that compose these operations into idempotent `ensure_*` start states. These flows are owned by this runner/domain layer, not by shared runtime packages or wrapper glue.
101
-
102
- For Perps, recipes should use the runner-provided `metamask.perps.start_state({ network, provider, page, market, positions, orders })` and `metamask.perps.teardown_state(...)` actions as the default reproducibility boundary. These actions compose primitive bulk operations such as `close_positions({ mode: "all" })` and `close_orders({ mode: "all" })` instead of multiplying one-off cleanup actions.
103
-
104
- ## Built-in Extension live adapters
105
-
106
- The first Extension adapter set is bundled under `library/actions/extension/` and talks directly to the Chrome extension page target over CDP. It does not execute a second recipe graph. The v1 runner still owns workflow traversal; each script only fulfills one manifest-declared action.
107
-
108
- Runtime input:
109
-
110
- ```text
111
- node.cdp_port | CDP_PORT | RECIPE_CDP_PORT
112
- ```
113
-
114
- Optional autolaunch input for existing Extension builds:
115
-
116
- ```text
117
- METAMASK_RECIPE_EXTENSION_AUTOLAUNCH=1
118
- METAMASK_RECIPE_EXTENSION_LAUNCH_EXISTING_DIST=1
119
- node.launch_existing_dist=true
120
- ```
121
-
122
- When enabled, the adapter reuses the requested CDP port if a compatible extension target exists; otherwise it launches Chrome from the target checkout's existing `dist/chrome` without rebuilding the product. The runtime copy, profile, logs, and `runtime.json` are written under `context.artifactsDir/extension-runtime/`.
123
-
124
- CLI equivalent:
125
-
126
- ```bash
127
- mm-harness run <recipe.json> --adapter extension --cdp-port 6664 --launch-existing-dist --artifacts-dir <dir>
128
- ```
129
-
130
- The CLI maps `--cdp-port` to `CDP_PORT`/`RECIPE_CDP_PORT` and maps `--launch-existing-dist` to `METAMASK_RECIPE_EXTENSION_AUTOLAUNCH=1` for the duration of the recipe run.
131
-
132
- Currently implemented Extension actions:
133
-
134
- ```text
135
- ui.navigate # extension: page alias or hash/path/url
136
- metamask.perps.read_positions
137
- metamask.perps.read_orders
138
- metamask.perps.close_positions # primitive bulk close selected positions
139
- metamask.perps.close_orders # primitive bulk cancel selected orders
140
- metamask.perps.place_order
141
- metamask.perps.assert_positions
142
- metamask.perps.assert_orders
143
- metamask.perps.ensure_positions # high-level read/close/place/assert wrapper
144
- metamask.perps.ensure_orders # high-level read/cancel/assert wrapper
145
- ui.press
146
- ui.scroll
147
- ui.wait_for
148
- ui.screenshot
149
- ```
150
-
151
- Navigation supports a small discoverable `page` alias set (`home`, `perps`, `perps-market`) plus raw extension hash/url fallback. Check the action manifest before hardcoding routes.
152
-
153
- Task-specific UI styling checks, such as one ticket proving a banner color or placement, must not be implemented as reusable `metamask.perps.*` actions. Use official `ui.wait_for` for reusable presence/absence checks plus screenshot/task-local validation evidence for that ticket.
154
-
155
- Read-only position checks use `stateHooks.submitRequestToBackground('perpsGetPositions', [{ skipCache: true }])`. State-changing actions prefer UI interaction through CDP mouse/keyboard events. Bulk cleanup primitives may call product background APIs such as `perpsClosePositions` or `perpsCancelOrders` when the UI control is unavailable; this is a supported app/API path, not direct state mutation. Adapters must not mutate Redux/React state, DOM state, local storage, or controller internals to fabricate proof.
156
-
157
- ## Built-in Mobile live adapters
158
-
159
- The Mobile adapter is bundled under `library/actions/mobile/`. Its CDP bridge, wallet setup, target discovery, and screenshot helpers run from the runner runtime; the Mobile checkout must not own harness control scripts. The app still needs a development-only in-app bridge/HUD overlay when a historical checkout does not expose the required `globalThis.__AGENTIC__` hooks.
160
-
161
- Runtime input:
162
-
163
- ```text
164
- node.watcher_port | node.metro_port | node.cdp_port | WATCHER_PORT | CDP_PORT | RECIPE_CDP_PORT
165
- node.simulator | node.ios_simulator | IOS_SIMULATOR
166
- node.android_device | ANDROID_DEVICE
167
- ```
168
-
169
- Currently implemented Mobile actions:
170
-
171
- ```text
172
- ui.navigate # mobile: page alias or route/screen + params
173
- metamask.perps.read_positions
174
- metamask.perps.read_orders
175
- metamask.perps.close_positions # primitive bulk close selected positions
176
- metamask.perps.close_orders # primitive bulk cancel selected orders
177
- metamask.perps.place_order
178
- metamask.perps.assert_positions
179
- metamask.perps.assert_orders
180
- metamask.perps.ensure_positions # high-level read/close/place/assert wrapper
181
- metamask.perps.ensure_orders # high-level read/cancel/assert wrapper
182
- ui.press
183
- ui.scroll
184
- ui.wait_for
185
- ui.screenshot
186
- ```
187
-
188
- Navigation supports a small discoverable `page` alias set (`home`, `perps`, `perps-market`) plus raw React Navigation route/params fallback. Check the action manifest before hardcoding routes.
189
-
190
- Read-only position checks use `Engine.context.PerpsController.getPositions()` through Hermes CDP. State-changing Perps actions use supported controller APIs (`placeOrder`, `closePositions`) through the same app bridge rather than mutating Redux/React/local storage. Mobile `ui.press` uses `press-test-id` for `test_id`/`testID`/`selector` and `press-text` for visible `text`; scrolling uses `scroll-view`. Screenshot capture uses `xcrun simctl io <simulator> screenshot` for iOS simulator proof.
@@ -1,47 +0,0 @@
1
- # Package Boundaries
2
-
3
- This package intentionally stays as **one npm package** with a clear internal
4
- split. Splitting into two packages now would make users choose between packages
5
- before the runtime API is stable. Instead, keep one install surface and separate
6
- responsibilities inside the repo.
7
-
8
- ## Internal split
9
-
10
- | Area | Owns | Does not own |
11
- |---|---|---|
12
- | Recipe layer | Action manifests, reusable recipes, typed runner binding, Mobile/Extension live adapters, proof semantics. | Starting Metro/Chrome, simulator boot, native builds, git cleanup. |
13
- | Runtime lifecycle layer | Harness install/cleanup, Metro/dev-client launch, bundle prewarm, Chrome/CDP launch, fixture/profile setup, readiness gates. | Recipe graph execution, action vocabulary decisions, task-specific proof logic. |
14
-
15
- ## Stable command contract
16
-
17
- Keep the public package simple:
18
-
19
- ```bash
20
- mm-harness launch ios ... # runtime lifecycle, then readiness proof (mobile)
21
- mm-harness launch ... # runtime lifecycle, then readiness proof (extension)
22
- mm-harness run <recipe.json> ... # recipe execution only
23
- ```
24
-
25
- Wrappers such as skills or slot farms should call those commands. They should not
26
- copy adapter scripts or reimplement Metro/Chrome launch behavior.
27
-
28
- ## Why not two packages yet?
29
-
30
- A future split may be useful, for example:
31
-
32
- - `@metamask/recipe-runner` for manifests/adapters/proof execution;
33
- - `@metamask/recipe-runtime` for Mobile/Extension sandbox launch.
34
-
35
- Do that only after the runtime CLI is stable, all wrappers call it exclusively
36
- (no copied adapter scripts), and the two areas have gone several releases
37
- without a change that touches both. Until then, two packages would likely
38
- increase confusion and version skew.
39
-
40
- ## Change discipline
41
-
42
- 1. Prefer moving behavior into the runner before changing farms/skills.
43
- 2. Keep compatibility wrappers when renaming files or commands.
44
- 3. Validate both paths after runtime changes:
45
- - direct runner/skill path;
46
- - Farmslot/Command Center prepare path.
47
- 4. Do not move files just for tidiness if callers still depend on old paths.