@deeeed/metamask-harness 0.17.5 → 0.19.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 (169) hide show
  1. package/CHANGELOG.md +1059 -0
  2. package/README.md +91 -140
  3. package/adapters/core/inject.sh +1 -6
  4. package/adapters/extension/console-tail.mjs +55 -24
  5. package/adapters/extension/ensure-browser.sh +6 -1
  6. package/adapters/extension/inject.mjs +7 -13
  7. package/adapters/extension/launch-browser.cjs +7 -1
  8. package/adapters/extension/launch-webpack.cjs +83 -0
  9. package/adapters/extension/launch.sh +8 -11
  10. package/adapters/extension/lib/chrome-args.cjs +8 -1
  11. package/adapters/extension/lib/macos-focus.cjs +32 -0
  12. package/adapters/extension/live.sh +12 -21
  13. package/adapters/extension/reattach.sh +1 -0
  14. package/adapters/extension/seed-fixture.sh +4 -12
  15. package/adapters/extension/sidepanel-toggle.sh +4 -1
  16. package/adapters/extension/stamp-runtime-title.cjs +58 -0
  17. package/adapters/extension/start-watch.sh +17 -4
  18. package/adapters/extension/stop-viewers.sh +1 -1
  19. package/adapters/extension/sync-webpack-dist.cjs +107 -0
  20. package/adapters/extension/verify.sh +2 -2
  21. package/adapters/manifest.json +53 -37
  22. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +16 -0
  23. package/adapters/mobile/bridge-runtime/console-forwarder.cjs +1 -1
  24. package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +3 -1
  25. package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +2 -3
  26. package/adapters/mobile/cleanup.sh +16 -176
  27. package/adapters/mobile/inject.sh +91 -671
  28. package/adapters/mobile/launch-console-forwarder.cjs +39 -0
  29. package/adapters/mobile/open-device.sh +45 -7
  30. package/adapters/mobile/start-console-forwarder.sh +70 -0
  31. package/adapters/mobile/start-metro.sh +0 -41
  32. package/adapters/mobile/verify.sh +34 -83
  33. package/adapters/mobile/wait-for-bridge.sh +22 -8
  34. package/adapters/shared/harness-source-fingerprint.mjs +14 -12
  35. package/adapters/shared/resolve-slot-ports-core.mjs +17 -6
  36. package/adapters/shared/resolve-slot-ports.sh +17 -5
  37. package/adapters/shared/update-check-worker.mjs +43 -0
  38. package/bin/mm-harness +21 -2
  39. package/dist/adapters/core/surface.js +4 -1
  40. package/dist/adapters/extension/console-capture.js +95 -0
  41. package/dist/adapters/extension/product-config.js +110 -0
  42. package/dist/adapters/extension/runtime-decision.js +20 -2
  43. package/dist/adapters/extension/surface.js +22 -3
  44. package/dist/adapters/harness-freshness.js +49 -0
  45. package/dist/adapters/mobile/perps-env.js +43 -3
  46. package/dist/adapters/mobile/prepare.js +39 -7
  47. package/dist/adapters/mobile/surface.js +5 -2
  48. package/dist/adapters/resolve-slot-ports.js +2 -2
  49. package/dist/adapters/slot-ports.js +13 -16
  50. package/dist/adapters.js +56 -16
  51. package/dist/checkout-lock.js +27 -2
  52. package/dist/cli-color.js +19 -0
  53. package/dist/cli-commands.js +1 -1
  54. package/dist/cli.js +7 -18
  55. package/dist/command-contract.js +462 -0
  56. package/dist/command-journal.js +263 -0
  57. package/dist/commands/call.js +252 -57
  58. package/dist/commands/check.js +10 -4
  59. package/dist/commands/completion-candidates.js +17 -22
  60. package/dist/commands/device-target.js +27 -12
  61. package/dist/commands/doctor.js +106 -25
  62. package/dist/commands/fixtures.js +142 -35
  63. package/dist/commands/last.js +60 -0
  64. package/dist/commands/launch/extension.js +40 -17
  65. package/dist/commands/launch/index.js +207 -63
  66. package/dist/commands/launch/mobile.js +2 -0
  67. package/dist/commands/list-executables.js +187 -29
  68. package/dist/commands/logs.js +8 -6
  69. package/dist/commands/manifest.js +286 -35
  70. package/dist/commands/parse-args.js +68 -4
  71. package/dist/commands/provision.js +10 -4
  72. package/dist/commands/run-engine.js +772 -264
  73. package/dist/commands/run-report.js +12 -3
  74. package/dist/commands/run.js +378 -85
  75. package/dist/commands/shared.js +76 -4
  76. package/dist/commands/status-probe.js +4 -1
  77. package/dist/commands/status.js +2 -1
  78. package/dist/commands/stop.js +7 -2
  79. package/dist/commands/update.js +16 -28
  80. package/dist/completions-cache.js +1 -1
  81. package/dist/doctor.js +57 -10
  82. package/dist/harness.js +47 -137
  83. package/dist/heal-bounds.js +7 -2
  84. package/dist/json-stream.js +57 -0
  85. package/dist/live-adapter-contract.js +138 -32
  86. package/dist/manifest.js +161 -1
  87. package/dist/mm-harness-cli.js +146 -73
  88. package/dist/paths.js +2 -5
  89. package/dist/recipe-security.js +178 -0
  90. package/dist/run-diagnostics.js +261 -0
  91. package/dist/run-recording.js +1 -1
  92. package/dist/runner.js +140 -9
  93. package/docs/CONTRIBUTING.md +136 -0
  94. package/docs/QA.md +184 -0
  95. package/docs/RECIPES.md +122 -0
  96. package/docs/SECURITY.md +88 -0
  97. package/library/README.md +7 -3
  98. package/library/actions/core/perps/_controller.mjs +43 -56
  99. package/library/actions/core/perps/assert_orders.mjs +6 -7
  100. package/library/actions/core/perps/assert_positions.mjs +6 -7
  101. package/library/actions/core/perps/close_orders.mjs +2 -0
  102. package/library/actions/core/perps/close_positions.mjs +2 -0
  103. package/library/actions/core/perps/ensure_orders.mjs +4 -2
  104. package/library/actions/core/perps/ensure_positions.mjs +4 -2
  105. package/library/actions/core/perps/place_order.mjs +7 -3
  106. package/library/actions/core/perps/read_account.mjs +2 -2
  107. package/library/actions/core/perps/read_orders.mjs +2 -1
  108. package/library/actions/core/perps/read_positions.mjs +2 -1
  109. package/library/actions/core/wallet/list_accounts.mjs +95 -0
  110. package/library/actions/extension/perps/assert_orders.mjs +2 -1
  111. package/library/actions/extension/perps/assert_positions.mjs +2 -1
  112. package/library/actions/extension/perps/perps.mjs +43 -14
  113. package/library/actions/extension/platform/cdp.mjs +1 -0
  114. package/library/actions/extension/wallet/list_accounts.mjs +41 -0
  115. package/library/actions/mobile/perps/assert_orders.mjs +2 -1
  116. package/library/actions/mobile/perps/assert_positions.mjs +2 -1
  117. package/library/actions/mobile/perps/perps.mjs +40 -12
  118. package/library/actions/mobile/wallet/list_accounts.mjs +37 -0
  119. package/library/library.json +1 -1
  120. package/library/manifests/core.action-manifest.json +1214 -396
  121. package/library/manifests/extension.action-manifest.json +1635 -728
  122. package/library/manifests/mobile.action-manifest.json +1740 -727
  123. package/library/recipes/app/lifecycle.android-smoke.mobile.recipe.json +63 -81
  124. package/library/recipes/perps/clean-market-testnet.core.recipe.json +44 -0
  125. package/library/recipes/perps/clean-market-testnet.recipe.json +49 -0
  126. package/library/recipes/perps/lifecycle.recipe.json +136 -180
  127. package/library/recipes/perps/order-lifecycle.core.recipe.json +71 -67
  128. package/library/recipes/perps/performance.background-resume.mobile.recipe.json +51 -67
  129. package/library/recipes/perps/performance.cold-start.mobile.recipe.json +51 -67
  130. package/library/recipes/perps/performance.mobile.recipe.json +37 -51
  131. package/library/recipes/perps/performance.warm-start.mobile.recipe.json +44 -59
  132. package/library/recipes/perps/read-markets.core.recipe.json +29 -31
  133. package/library/recipes/perps/smoke.core.recipe.json +29 -32
  134. package/library/recipes/perps/smoke.extension.recipe.json +41 -44
  135. package/library/recipes/perps/smoke.mobile.recipe.json +42 -44
  136. package/library/recipes/perps/trading-lifecycle.core.recipe.json +69 -65
  137. package/library/recipes/runner/action-validation.extension.recipe.json +312 -398
  138. package/library/recipes/runner/action-validation.mobile.recipe.json +316 -402
  139. package/library/recipes/runner/smoke.core.recipe.json +25 -0
  140. package/library/recipes/runner/smoke.extension.recipe.json +23 -24
  141. package/library/recipes/runner/smoke.mobile.recipe.json +23 -24
  142. package/library/recipes/wallet/smoke.extension.recipe.json +40 -0
  143. package/library/recipes/wallet/smoke.mobile.recipe.json +40 -0
  144. package/package.json +12 -5
  145. package/scripts/completions.sh +8 -11
  146. package/scripts/validate-human-outcomes.mjs +169 -0
  147. package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +0 -185
  148. package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +0 -1662
  149. package/adapters/mobile/overlay/compat/README.md +0 -28
  150. package/adapters/mobile/overlay/compat/rn81-message-event-source.patch +0 -42
  151. package/adapters/shared/resolve-farmslot-ports-core.mjs +0 -3
  152. package/adapters/shared/resolve-farmslot-ports.mjs +0 -5
  153. package/adapters/shared/resolve-farmslot-ports.sh +0 -7
  154. package/dist/adapters/extension/harness-freshness.js +0 -39
  155. package/dist/commands/flows.js +0 -62
  156. package/docs/ADAPTER-SURFACE.md +0 -119
  157. package/docs/CHEATSHEET.md +0 -61
  158. package/docs/CLI-SPEC.md +0 -1098
  159. package/docs/CODE-MAP.md +0 -62
  160. package/docs/DEBUG-HANDOVER.md +0 -36
  161. package/docs/MENTAL-MODEL.md +0 -295
  162. package/docs/UX-PRINCIPLES.md +0 -64
  163. package/docs/architecture.md +0 -398
  164. package/docs/live-adapter-contract.md +0 -188
  165. package/docs/package-boundaries.md +0 -47
  166. package/docs/perps-flow-catalog.md +0 -235
  167. package/docs/recipe-libraries.md +0 -301
  168. package/docs/runtime-file-conventions.md +0 -36
  169. package/library/flows/perps.flows.json +0 -64
@@ -1,398 +0,0 @@
1
- # MetaMask Recipe Runner Architecture
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
-
38
- This repo is the MetaMask-specific adapter layer for Recipe Protocol v1. It is
39
- not the protocol engine, not a skills repo, not a slot farm, and not product
40
- code. Its job is to publish reviewable MetaMask capabilities and run them
41
- against a local Mobile or Extension checkout without committing harness runtime
42
- into that checkout.
43
-
44
- The core model is standalone: install or check out this runner, point it at a
45
- MetaMask checkout, and run `mm-harness`. Farm/slot orchestration is only a
46
- way to scale the same loop across many checkouts, machines, ports, and agents;
47
- it is not required to understand or use the runner.
48
-
49
- ## TL;DR
50
-
51
- The four questions that come up whenever this repo needs explaining.
52
-
53
- **Responsibility split.** This runner owns the logic; skills and farms are a
54
- minimum overlay that call its CLI. Rule of thumb: if a skill's shell script is
55
- doing more than parsing flags and calling `mm-harness`, that logic
56
- belongs in this runner instead. Concrete example in flight: the
57
- `recipe-harness` skill currently locates and execs runner internals in
58
- hundreds of lines of bash (resolve runner source, dispatch to
59
- `adapters/<platform>/{inject,cleanup}.{sh,mjs}` — `.sh` for Mobile/Core,
60
- `.mjs` for Extension); the fix is a
61
- [`mm-harness <install|verify|cleanup|live>`](CLI-SPEC.md) command here, so the
62
- skill thins to a few lines that call it. Same pattern applies to every other
63
- `recipe-*` skill over time.
64
-
65
- **Language policy — bash vs ts vs mjs vs cjs.** Current mix: 65 `.sh`, 62
66
- `.mjs`, 17 `.ts`, 9 `.cjs` (excluding `node_modules`).
67
-
68
- | Extension | Where | Use for | Why |
69
- |---|---|---|---|
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 |
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 |
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 |
74
-
75
- The mix is bash-heavy today because sandbox setup crosses OS/device boundaries
76
- (see "Why there are shell scripts" below) — that is current reality, not the
77
- target ratio. The direction is less bash over time: when a shell helper starts
78
- accumulating domain behavior, move it into `.ts` or a focused `.mjs` adapter
79
- (see [Runtime File Conventions](runtime-file-conventions.md) for the full
80
- rule).
81
-
82
- **Packaging — one package, not several.** This stays one npm package while the
83
- runtime API is still moving; see [Package Boundaries](package-boundaries.md)
84
- for the full rationale. Splitting now would force every wrapper (skills,
85
- farmslot) to pin two coordinated versions before the boundary between "recipe
86
- execution" and "runtime lifecycle" has stabilized — coordination cost for no
87
- current benefit. Split when the runtime CLI contract is stable, all wrappers
88
- call it exclusively (no copied adapter scripts), and the two areas have gone
89
- several releases without a change that touches both.
90
-
91
- ## Layer map (front door → engine → schema)
92
-
93
- The whole stack is three layers with a strictly one-way dependency. `mm-harness`
94
- is the MetaMask-facing **front door**; underneath it the runner is a thin
95
- **adapter layer** over a fat generic **engine** (`@farmslot/recipe-harness`) and
96
- **schema** (`@farmslot/protocol`). The runner never re-implements engine logic —
97
- it imports it.
98
-
99
- ```text
100
- mm-harness (the one bin — no per-platform binaries) ← front door: one verb vocabulary
101
- │ launch · logs · debug · fixtures (daily loop) · run/flows/doctor/actions/manifest (prove)
102
- │ install/verify/cleanup/live (runtime overlay lifecycle)
103
-
104
- metamask-recipe-runner (MetaMask ADAPTER layer) ← this repo
105
- │ MetaMask action manifests, metamask.* live adapters, Mobile/Extension
106
- │ runtime overlay install, runtime health/decision probes
107
-
108
- @farmslot/recipe-harness (GENERIC engine) ← npm dependency
109
- │ recipe graph execution, official ui.* transports, RecordingTarget
110
- │ evidence framework, runtime modules, generic run/flows/validate CLI
111
-
112
- @farmslot/protocol (GENERIC schema) ← npm dependency
113
- │ Recipe v1 schema, action-manifest document, artifact contract
114
-
115
- MetaMask app under test
116
- │ local debug runtime only; product source should not own runner logic
117
-
118
- summary.json · trace.json · artifact-manifest.json · screenshots/logs
119
- ```
120
-
121
- **Dependency direction is one-way and provable.** The runner *depends on*
122
- `@farmslot/recipe-harness` + `@farmslot/protocol` (see `package.json`), and
123
- `src/**` *imports* the generic contracts rather than forking them:
124
-
125
- - `src/cli.ts` imports `RecipeRunResult` from `@farmslot/recipe-harness`
126
- and delegates library `flows` to the harness CLI (`importRecipeHarnessCli`).
127
- - `src/runner.ts` wires `metamask.*` adapters INTO the farmslot
128
- `RecipeRunner`; it does not implement graph execution.
129
- - `src/manifest.ts` loads *MetaMask* manifests typed by the *farmslot*
130
- protocol document type.
131
- - `src/recording-target.ts` is a MetaMask provider over the farmslot
132
- `RecordingTarget` contract.
133
-
134
- **The invariant both repos assert:** farmslot stays MetaMask-free; the runner
135
- never re-implements engine logic, only binds to it. Decision lens for placing any
136
- new capability: *would a non-MetaMask project reuse this unchanged?* → yes =
137
- generic (farmslot); encodes MetaMask app knowledge = runner.
138
-
139
- > Note on naming: "harness" refers to the tool (`mm-harness`) and the generic
140
- > engine package (`@farmslot/recipe-harness`). The per-checkout files the tool
141
- > installs into a target are the **runtime overlay** (`install`/`verify`/
142
- > `cleanup`/`live`), never "the harness" — see [CLI-SPEC.md](CLI-SPEC.md).
143
-
144
- ## One-minute model
145
-
146
- ```text
147
- human CLI / optional skill wrapper
148
- │ resolve + invoke
149
-
150
- metamask-recipe-runner
151
- │ MetaMask action manifests, live adapters, runtime overlay install, runtime probes
152
-
153
- Recipe harness package
154
- │ generic graph execution, official ui.* transports, traces, artifacts
155
-
156
- Recipe protocol package
157
- │ Recipe v1 schema, manifest contract, artifact contract
158
-
159
- MetaMask app under test
160
- │ local debug runtime only; product source should not own runner logic
161
-
162
- summary.json · trace.json · artifact-manifest.json · screenshots/logs
163
- ```
164
-
165
- Dependency direction is one-way. Wrappers call the runner; the runner calls the
166
- shared harness/protocol packages; product apps are only driven at runtime.
167
-
168
- ## Package shape
169
-
170
- This repo remains one npm package for now, but it has two internal areas: recipe execution and runtime lifecycle. See [Package Boundaries](package-boundaries.md) for the stability policy and why we are not splitting packages yet.
171
-
172
- ## The two subsystems
173
-
174
- This repo has two intentionally different kinds of code. Keeping them separate
175
- is the main way to understand the repository.
176
-
177
- | Subsystem | Question it answers | Primary files | Should contain | Should not contain |
178
- |---|---|---|---|---|
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 |
181
-
182
- When reviewing a change, first decide which subsystem it touches. Recipe changes
183
- should be validated against manifests and action artifacts. Runtime lifecycle changes should be validated by install/launch/live/verify
184
- behavior on a real checkout. Some commands cross the boundary, but they should
185
- do so by delegating: sandbox helpers get the runtime ready, then
186
- `mm-harness run` executes the recipe.
187
-
188
- ## Ownership boundaries
189
-
190
- | Layer | Owns | Must not own |
191
- |---|---|---|
192
- | Human CLI / optional wrapper | Target selection, runner invocation, evidence handoff | Copied adapter scripts, recipe graph execution, product runtime logic |
193
- | This runner | MetaMask action manifests, `metamask.*` adapters, Mobile/Extension harness install, runtime health/decision commands | Shared Recipe v1 schema, generic `ui.*` semantics, task-specific acceptance criteria |
194
- | `Recipe harness package` | Recipe graph execution, standard core/ui adapters, trace/summary/artifact writing | MetaMask wallet/Perps behavior |
195
- | `Recipe protocol package` | Recipe/manifest/artifact schemas | Runtime control or product-specific actions |
196
- | Product checkout | App code and debug hooks exposed by the app | Harness scripts, runner copy, skills, private workflow logic |
197
-
198
- Rule of thumb: if code describes **what MetaMask can do**, it belongs here. If it
199
- describes **how Recipe v1 works**, it belongs in the shared protocol/runtime packages. If it
200
- describes **how an agent should work**, it belongs in skills.
201
-
202
- ## Key files and directories
203
-
204
- | Path | Responsibility |
205
- |---|---|
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`. |
210
- | `library/manifests/*.action-manifest.json` | Reviewable capability contract. A recipe may only call declared actions. |
211
- | `library/actions/mobile/` | Mobile action implementations. Talks to the runner bridge and app-exposed `globalThis.__AGENTIC__` hooks. |
212
- | `library/actions/extension/` | Extension action implementations. Talks to Chrome/extension pages over CDP. |
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. |
219
- | `library/recipes/` | Reusable smoke/runner.action-validation recipes only. Task-specific proof recipes stay task-local. |
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). |
221
- | `docs/` | Runner architecture, contracts, and operational conventions. |
222
-
223
- ## Runtime paths and installed harnesses
224
-
225
- Defaults are centralized in `adapters/shared/path-defaults.json`:
226
-
227
- ```json
228
- {
229
- "recipeHarnessRoot": "temp/recipe/harness",
230
- "recipeRuntimeDir": "temp/recipe/runtime"
231
- }
232
- ```
233
-
234
- All shell, standalone Node, and TypeScript code must read these through the
235
- shared helpers instead of hardcoding defaults. Environment overrides are allowed
236
- through `RECIPE_HARNESS_ROOT` and `RECIPE_RUNTIME_DIR`, but they must stay safe
237
- relative paths.
238
-
239
- Install commands write a small runtime package into the target checkout:
240
-
241
- ```text
242
- <target>/<recipeHarnessRoot>/<adapter>/
243
- manifest.json installed source/revision/cleanup metadata
244
- action-manifest.json snapshot of the adapter manifest
245
- runner/bin/mm-harness delegate back to the resolved runner source
246
- runner/recipes/ reusable recipe snapshot
247
- scripts/ adapter runtime helpers copied from this repo
248
- ```
249
-
250
- The installed harness exists so a running slot has stable helper paths even when
251
- called from skills, orchestration hooks, or a human shell. The source of truth remains
252
- this runner.
253
-
254
- ## Recipe execution vs sandbox lifecycle
255
-
256
- `mm-harness run <recipe.json> --adapter ...` is the recipe path. It creates
257
- a shared Recipe runner (`src/runner.ts`), validates the recipe against the
258
- manifest, executes nodes, and writes artifacts. If a bug is about action fields,
259
- trace output, adapter semantics, or whether a recipe proves a claim, start in
260
- `library/manifests/`, `src/`, `library/actions/`, and `library/recipes/`.
261
-
262
- `prepare`, `launch`, `live`, `verify`, `status`, `decision`, and `ready` are
263
- sandbox lifecycle paths. They give the agent a reproducible local app session:
264
- Mobile with Metro/dev-client/simulator and the bridge online; Extension with an
265
- isolated browser profile, unpacked extension loaded, and a known home/popup-style
266
- UI target. If a bug is about Metro, bundle prewarm, simulator launch, Chrome CDP,
267
- Extension full-screen vs popup presentation, build freshness, wallet fixture
268
- placement, git-exclude, or cleanup, start in `adapters/{mobile,extension,core}/`.
269
-
270
- Do not put recipe graph traversal into shell scripts. Shell scripts may prepare
271
- or inspect the sandboxed runtime, then delegate graph execution to
272
- `mm-harness run`.
273
-
274
- ## HUD vs bridge vs product hooks
275
-
276
- These names are easy to mix up; they are different concerns.
277
-
278
- | Term | What it is | Why it exists |
279
- |---|---|---|
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. |
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. |
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. |
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. |
284
-
285
- The HUD does not control the app. The bridge/CDP control the app. The HUD only
286
- renders proof context.
287
-
288
- ## Mobile runtime shape
289
-
290
- Mobile has the most moving parts because React Native does not expose a browser
291
- DOM by default.
292
-
293
- ```text
294
- mm-harness launch ios|android
295
- │ prepareMobile() in-process → yarn-setup / start-metro / open-device leaves
296
-
297
- adapters/mobile/bridge-runtime/cdp-bridge.cjs
298
- │ connects to Hermes / RN debug runtime
299
-
300
- globalThis.__AGENTIC__ inside the app
301
- │ route/status/wallet/ui commands + optional HUD rendering
302
-
303
- library/actions/mobile/{wallet,perps,ui,platform}/*.mjs
304
- ```
305
-
306
- Ideally the app would expose a product-owned debug automation surface directly,
307
- so the runner would not need to patch or inject Mobile client files at all. The
308
- current injection exists as a compatibility bridge: it lets recipes run against
309
- older Mobile versions, historical PR branches, and eval/replay runs that do not yet include that
310
- client-side automation surface.
311
-
312
- The Mobile injection currently may touch development-only product files on older
313
- checkouts to install the `AgenticService`, navigation hook, and HUD mount. That
314
- is the fragile compatibility path, not the desired long-term product contract.
315
- Those product patches are local runtime state: never commit them to MetaMask
316
- Mobile. The runner also installs ignored helper files under
317
- `temp/recipe/harness/mobile`.
318
-
319
- Mobile `ensure_*` actions must be idempotent: if the wallet is already unlocked,
320
- `metamask.wallet.ensure_unlocked` should report success or converge cheaply, not
321
- fail because the starting state differed.
322
-
323
- ## Extension runtime shape
324
-
325
- Extension does not need an in-product source patch. The runner works through an
326
- unpacked `dist/chrome` build and Chrome CDP.
327
-
328
- ```text
329
- mme-recipe / adapters/extension/*.sh
330
- │ checks dist freshness, build health, fixture/profile state
331
-
332
- Chrome for Testing with --load-extension=<runtime-dist>
333
- │ CDP target discovery + deterministic extension id
334
-
335
- library/actions/extension/{wallet,perps,ui,platform}/*.mjs
336
- │ extension page/background hooks and UI events
337
- ```
338
-
339
- `runtime-launch --start-watch` is the clean-build path. Without `--start-watch`,
340
- verify can prove the existing runtime is reachable but may fail `dist-freshness`
341
- if `dist/chrome` does not match `HEAD`. That failure is intentional: it prevents
342
- silently proving stale product code.
343
-
344
- ## Why there are shell scripts
345
-
346
- The shell scripts are large because sandbox setup crosses OS/device boundaries:
347
- `simctl`, `adb`, Metro, Watchman, Chrome process flags, isolated browser
348
- profiles, git exclude files, symlink safety checks, and cleanup all live outside
349
- Node's typed domain logic. Their purpose is to give an agent a reliable app
350
- session, not to define recipe semantics.
351
-
352
- Allowed in shell:
353
-
354
- - parsing CLI flags for lifecycle commands;
355
- - calling OS/device tools;
356
- - copying/removing installed harness files;
357
- - starting/stopping/reusing local dev servers;
358
- - writing small runtime summaries from command results.
359
-
360
- Not allowed in shell:
361
-
362
- - Recipe v1 graph execution;
363
- - MetaMask domain semantics that can live in `src/**/*.ts` or `library/actions/**/*.mjs`;
364
- - duplicated action manifest logic;
365
- - product-specific business decisions beyond runtime boot/health checks.
366
-
367
- When a shell helper starts accumulating domain behavior, move that behavior into
368
- TypeScript or a focused `.mjs` adapter and keep shell as the launcher.
369
-
370
- ## Adding or changing capabilities
371
-
372
- 1. Add/adjust the shared capability in both Mobile and Extension manifests when
373
- the concept exists on both platforms.
374
- 2. Implement durable behavior under `library/actions/<platform>/<domain>/`.
375
- 3. Keep parameterized actions instead of multiplying action names.
376
- 4. Ensure every `ensure_*` action proves a postcondition.
377
- 5. Use official `ui.*` actions and screenshot claims for visible acceptance
378
- criteria; do not add task-specific `metamask.*` actions for exact copy,
379
- styling, ticket IDs, or one-off selectors.
380
- 6. Update smoke/runner.action-validation recipes only when the capability is reusable.
381
-
382
- ## Standalone use first; farm later
383
-
384
- This runner should make sense without any slot farm:
385
-
386
- 1. choose a local MetaMask Mobile or Extension checkout;
387
- 2. run `mm-harness launch <platform>` (or `mm-harness install` for the overlay only);
388
- 3. run `mm-harness doctor` (or the advanced `runtime-health`);
389
- 4. run `mm-harness run <recipe.json> --adapter <platform> --artifacts-dir <dir>`.
390
-
391
- Skills are optional workflow wrappers around that same CLI. A wrapper may resolve
392
- the runner source and package evidence, but it should dispatch `install`,
393
- `launch`, `live`, `verify`, and `cleanup` to this repo or to the installed
394
- harness helper. It should not carry Mobile or Extension adapter scripts.
395
-
396
- Farm/slot orchestration belongs one layer outside this runner. It can scale the
397
- standalone loop by choosing checkouts, machines, ports, simulators, and agents,
398
- but it should not change the runner contract or copy runner implementation.
@@ -1,188 +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
- Legacy external `.js` adapters are still resolved for compatibility, and `.sh` remains available for edge orchestration. New committed adapter code should use grouped `.mjs` modules. Fully-qualified flat filenames are still searched after grouped paths, but new adapter code should use grouped modules. Do not add `ui.*` files here; official UI actions go through shared base transports. Examples:
23
-
24
- ```text
25
- library/actions/extension/perps/ensure_positions.mjs
26
- library/actions/extension/perps/close_positions.mjs
27
- library/actions/extension/perps/close_orders.mjs
28
- library/actions/mobile/perps/place_order.mjs
29
- library/actions/mobile/wallet/ensure_unlocked.mjs
30
- ```
31
-
32
- 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.
33
-
34
- Input shape:
35
-
36
- ```json
37
- {
38
- "schemaVersion": 1,
39
- "platform": "mobile|extension",
40
- "action": "metamask.perps.ensure_positions",
41
- "node": {},
42
- "context": {
43
- "nodeId": "ensure-clean",
44
- "projectRoot": "/path/to/product",
45
- "artifactsDir": "/path/to/artifacts"
46
- },
47
- "outputPath": "/tmp/.../output.json"
48
- }
49
- ```
50
-
51
- 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.
52
-
53
- 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.
54
-
55
- ## Controller/API calls vs visible UI proof
56
-
57
- Recipe authors should choose the layer based on what must be proven:
58
-
59
- | Need | Use | Rule |
60
- |---|---|---|
61
- | 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. |
62
- | Read-only state proof | `metamask.*.read_*` or `metamask.*.assert_*` | Must return redacted live state in trace output. |
63
- | 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. |
64
- | Ticket-specific visual detail | task-local recipe assertions/evidence | Do not add a reusable action only for one ticket. |
65
-
66
- ## Shared action-surface boundaries
67
-
68
- The manifest is a durable capability contract, not a place to encode one
69
- ticket's acceptance criteria. Do not add shared `metamask.*` actions for ticket
70
- IDs, POCs, exact test IDs, exact copy, styling, placement, or other one-off UI
71
- proof needs.
72
-
73
- Use:
74
-
75
- - official `ui.*` actions for reusable presence, input, scroll, and screenshot
76
- behavior;
77
- - screenshot `claims` for visual, copy, and layout proof;
78
- - task-local composed flows under the task artifact directory when a ticket
79
- needs a reusable helper for that ticket only;
80
- - safe direct CDP/controller calls for read/assert or supported setup paths,
81
- never state fabrication.
82
-
83
- Add or keep a shared action only when it represents a durable parameterized
84
- domain capability useful across many tasks, such as `metamask.perps.start_state`,
85
- `metamask.perps.place_order`, `metamask.perps.close_positions`, or
86
- `metamask.perps.assert_positions`.
87
-
88
- `ui.scroll` is part of the current executable contract and runner.action-validation must
89
- prove both normal scrolling and `scroll_into_view` before screenshot capture.
90
- `ui.gesture` is intentionally not advertised yet; drag/swipe proof must wait
91
- until the shared runtime and this runner expose and validate that action on both
92
- platforms.
93
-
94
-
95
-
96
- ## Flow catalog follow-up
97
-
98
- 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.
99
-
100
- 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.
101
-
102
- ## Built-in Extension live adapters
103
-
104
- 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.
105
-
106
- Runtime input:
107
-
108
- ```text
109
- node.cdp_port | CDP_PORT | RECIPE_CDP_PORT
110
- ```
111
-
112
- Optional autolaunch input for existing Extension builds:
113
-
114
- ```text
115
- METAMASK_RECIPE_EXTENSION_AUTOLAUNCH=1
116
- METAMASK_RECIPE_EXTENSION_LAUNCH_EXISTING_DIST=1
117
- node.launch_existing_dist=true
118
- ```
119
-
120
- 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/`.
121
-
122
- CLI equivalent:
123
-
124
- ```bash
125
- mm-harness run <recipe.json> --adapter extension --cdp-port 6664 --launch-existing-dist --artifacts-dir <dir>
126
- ```
127
-
128
- 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.
129
-
130
- Currently implemented Extension actions:
131
-
132
- ```text
133
- ui.navigate # extension: page alias or hash/path/url
134
- metamask.perps.read_positions
135
- metamask.perps.read_orders
136
- metamask.perps.close_positions # primitive bulk close selected positions
137
- metamask.perps.close_orders # primitive bulk cancel selected orders
138
- metamask.perps.place_order
139
- metamask.perps.assert_positions
140
- metamask.perps.assert_orders
141
- metamask.perps.ensure_positions # high-level read/close/place/assert wrapper
142
- metamask.perps.ensure_orders # high-level read/cancel/assert wrapper
143
- ui.press
144
- ui.scroll
145
- ui.wait_for
146
- ui.screenshot
147
- ```
148
-
149
- 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.
150
-
151
- 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.
152
-
153
- 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.
154
-
155
- ## Built-in Mobile live adapters
156
-
157
- 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.
158
-
159
- Runtime input:
160
-
161
- ```text
162
- node.watcher_port | node.metro_port | node.cdp_port | WATCHER_PORT | CDP_PORT | RECIPE_CDP_PORT
163
- node.simulator | node.ios_simulator | IOS_SIMULATOR
164
- node.android_device | ANDROID_DEVICE
165
- ```
166
-
167
- Currently implemented Mobile actions:
168
-
169
- ```text
170
- ui.navigate # mobile: page alias or route/screen + params
171
- metamask.perps.read_positions
172
- metamask.perps.read_orders
173
- metamask.perps.close_positions # primitive bulk close selected positions
174
- metamask.perps.close_orders # primitive bulk cancel selected orders
175
- metamask.perps.place_order
176
- metamask.perps.assert_positions
177
- metamask.perps.assert_orders
178
- metamask.perps.ensure_positions # high-level read/close/place/assert wrapper
179
- metamask.perps.ensure_orders # high-level read/cancel/assert wrapper
180
- ui.press
181
- ui.scroll
182
- ui.wait_for
183
- ui.screenshot
184
- ```
185
-
186
- 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.
187
-
188
- 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. UI actions delegate to existing bridge capabilities such as `press-test-id` and `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.