@deeeed/metamask-harness 0.19.0 → 0.20.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 (43) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/adapters/extension/ensure-browser.sh +6 -4
  3. package/adapters/extension/launch-browser.cjs +6 -1
  4. package/adapters/extension/lib/chrome-args.cjs +11 -1
  5. package/adapters/extension/start-watch.sh +1 -1
  6. package/adapters/extension/verify.sh +17 -0
  7. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +33 -0
  8. package/adapters/mobile/open-device.sh +12 -1
  9. package/adapters/mobile/wait-for-bridge.sh +1 -1
  10. package/dist/adapters/extension/ensure-ready.js +7 -2
  11. package/dist/adapters/extension/runtime-decision.js +4 -6
  12. package/dist/adapters/extension/runtime.js +114 -17
  13. package/dist/adapters/mobile/prepare.js +40 -6
  14. package/dist/adapters.js +6 -1
  15. package/dist/command-contract.js +58 -5
  16. package/dist/commands/call.js +6 -3
  17. package/dist/commands/check.js +9 -2
  18. package/dist/commands/checklist.js +117 -14
  19. package/dist/commands/launch/extension.js +8 -3
  20. package/dist/commands/launch/index.js +38 -25
  21. package/dist/commands/launch/mobile.js +2 -2
  22. package/dist/commands/manifest.js +72 -5
  23. package/dist/commands/run-engine.js +7 -2
  24. package/dist/heal-bounds.js +1 -1
  25. package/dist/live-adapter-contract.js +15 -2
  26. package/dist/metamask-action-validation.js +45 -0
  27. package/dist/mm-harness-cli.js +7 -4
  28. package/docs/CONTRIBUTING.md +8 -0
  29. package/docs/RECIPES.md +15 -0
  30. package/library/actions/core/perps/assert_orders.mjs +16 -5
  31. package/library/actions/core/perps/assert_positions.mjs +16 -5
  32. package/library/actions/extension/perps/perps.mjs +111 -19
  33. package/library/actions/extension/platform/cdp.mjs +8 -3
  34. package/library/actions/extension/ui/navigate.mjs +239 -16
  35. package/library/actions/mobile/perps/perps.mjs +108 -10
  36. package/library/actions/mobile/ui/navigate.mjs +1 -1
  37. package/library/manifests/core.action-manifest.json +100 -11
  38. package/library/manifests/extension.action-manifest.json +80 -12
  39. package/library/manifests/mobile.action-manifest.json +85 -10
  40. package/library/recipes/perps/lifecycle.recipe.json +3 -9
  41. package/library/recipes/runner/action-validation.extension.recipe.json +5 -4
  42. package/package.json +5 -4
  43. package/scripts/completions.sh +2 -2
@@ -220,7 +220,7 @@
220
220
  ]
221
221
  },
222
222
  "ui.navigate": {
223
- "description": "Navigate with either raw extension url/hash/path or a small stable page alias. Discover supported aliases here before hardcoding routes.",
223
+ "description": "Navigate by semantic page intent when available; the adapter uses the current visible UI or a verified route. Raw url/hash/path values must be verified against the current app first.",
224
224
  "schema": {
225
225
  "type": "object",
226
226
  "properties": {
@@ -257,14 +257,16 @@
257
257
  "type": "object"
258
258
  },
259
259
  "timeout_ms": {
260
- "type": "number"
260
+ "type": "number",
261
+ "default": 20000,
262
+ "description": "Maximum time to discover and verify the requested page intent."
261
263
  }
262
264
  },
263
265
  "additionalProperties": false
264
266
  },
265
267
  "examples": [
266
268
  {
267
- "description": "Open Perps through the stable alias",
269
+ "description": "Ask the adapter to discover and open the current Perps entry point",
268
270
  "node": {
269
271
  "action": "ui.navigate",
270
272
  "page": "perps",
@@ -272,7 +274,7 @@
272
274
  }
273
275
  },
274
276
  {
275
- "description": "Open a Perps market through the stable alias",
277
+ "description": "Open a Perps market through the current verified adapter path",
276
278
  "node": {
277
279
  "action": "ui.navigate",
278
280
  "page": "perps-market",
@@ -281,7 +283,7 @@
281
283
  }
282
284
  },
283
285
  {
284
- "description": "Fallback to a raw extension hash when no alias exists",
286
+ "description": "Use a raw extension hash only after verifying it in the current app",
285
287
  "node": {
286
288
  "action": "ui.navigate",
287
289
  "hash": "#/perps-home",
@@ -782,7 +784,11 @@
782
784
  "type": "string"
783
785
  },
784
786
  "value": {
785
- "type": "string"
787
+ "type": [
788
+ "string",
789
+ "number"
790
+ ],
791
+ "description": "Text or a typed numeric recipe parameter; numbers are entered as their decimal text."
786
792
  },
787
793
  "text": {
788
794
  "type": "string"
@@ -1602,17 +1608,23 @@
1602
1608
  "long",
1603
1609
  "short"
1604
1610
  ],
1605
- "description": "Optional position/order side filter."
1611
+ "description": "Required order direction."
1606
1612
  },
1607
1613
  "timeout_ms": {
1608
1614
  "type": "number"
1609
1615
  },
1610
1616
  "amount": {
1611
- "type": "string",
1617
+ "type": [
1618
+ "string",
1619
+ "number"
1620
+ ],
1612
1621
  "description": "USD amount/notional alias."
1613
1622
  },
1614
1623
  "notional": {
1615
- "type": "string",
1624
+ "type": [
1625
+ "string",
1626
+ "number"
1627
+ ],
1616
1628
  "description": "USD notional alias."
1617
1629
  },
1618
1630
  "size": {
@@ -1963,11 +1975,25 @@
1963
1975
  "long",
1964
1976
  "short"
1965
1977
  ],
1966
- "description": "Optional position/order side filter."
1978
+ "description": "Required when state=open/present; otherwise filters selected positions."
1967
1979
  },
1968
1980
  "timeout_ms": {
1969
1981
  "type": "number"
1970
1982
  },
1983
+ "amount": {
1984
+ "type": [
1985
+ "string",
1986
+ "number"
1987
+ ],
1988
+ "description": "Explicit USD notional used only when creating a missing open position. Alias: notional."
1989
+ },
1990
+ "notional": {
1991
+ "type": [
1992
+ "string",
1993
+ "number"
1994
+ ],
1995
+ "description": "Alias for amount."
1996
+ },
1971
1997
  "state": {
1972
1998
  "type": "string",
1973
1999
  "enum": [
@@ -2003,6 +2029,17 @@
2003
2029
  "mode": "all",
2004
2030
  "intent": "Converge Perps positions to the requested state"
2005
2031
  }
2032
+ },
2033
+ {
2034
+ "description": "Ensure one ETH long position exists",
2035
+ "node": {
2036
+ "action": "metamask.perps.ensure_positions",
2037
+ "market": "ETH",
2038
+ "side": "long",
2039
+ "state": "open",
2040
+ "notional": "10",
2041
+ "intent": "Converge ETH positions to one explicit testnet precondition"
2042
+ }
2006
2043
  }
2007
2044
  ],
2008
2045
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
@@ -2015,7 +2052,7 @@
2015
2052
  {
2016
2053
  "name": "metamask.perps.ensure_orders",
2017
2054
  "owner": "metamask",
2018
- "description": "extension Default to testnet for Perps mutations; mainnet is read-only unless explicitly requested. Higher-level wrapper that reads selected orders, cancels when needed, then asserts final order state.",
2055
+ "description": "extension Converge selected testnet orders to open or absent, then independently assert the final state. Creating an open state uses a resting limit order.",
2019
2056
  "schema": {
2020
2057
  "type": "object",
2021
2058
  "properties": {
@@ -2093,11 +2130,30 @@
2093
2130
  "long",
2094
2131
  "short"
2095
2132
  ],
2096
- "description": "Optional position/order side filter."
2133
+ "description": "Required when state=open/present; otherwise filters selected orders."
2097
2134
  },
2098
2135
  "timeout_ms": {
2099
2136
  "type": "number"
2100
2137
  },
2138
+ "amount": {
2139
+ "type": [
2140
+ "string",
2141
+ "number"
2142
+ ],
2143
+ "description": "Explicit USD notional used only when creating a missing open order. Alias: notional."
2144
+ },
2145
+ "notional": {
2146
+ "type": [
2147
+ "string",
2148
+ "number"
2149
+ ],
2150
+ "description": "Alias for amount."
2151
+ },
2152
+ "leverage": {
2153
+ "type": "number",
2154
+ "default": 3,
2155
+ "description": "Testnet leverage used only when creating a missing open order."
2156
+ },
2101
2157
  "state": {
2102
2158
  "type": "string",
2103
2159
  "enum": [
@@ -2124,6 +2180,18 @@
2124
2180
  "mode": "all",
2125
2181
  "intent": "Converge Perps orders to the requested state"
2126
2182
  }
2183
+ },
2184
+ {
2185
+ "description": "Ensure one small resting ETH short order exists",
2186
+ "node": {
2187
+ "action": "metamask.perps.ensure_orders",
2188
+ "market": "ETH",
2189
+ "side": "short",
2190
+ "state": "open",
2191
+ "notional": 10,
2192
+ "leverage": 2,
2193
+ "intent": "Converge ETH open orders to one deterministic testnet precondition"
2194
+ }
2127
2195
  }
2128
2196
  ],
2129
2197
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
@@ -221,7 +221,7 @@
221
221
  ]
222
222
  },
223
223
  "ui.navigate": {
224
- "description": "Navigate with either raw React Navigation route/screen params or a small stable page alias. Discover supported aliases here before hardcoding routes.",
224
+ "description": "Navigate by semantic page intent through the adapter-owned current route mapping, then verify the live destination. Route drift fails loudly; raw route/screen params must be verified against the current app first.",
225
225
  "schema": {
226
226
  "type": "object",
227
227
  "properties": {
@@ -265,7 +265,7 @@
265
265
  },
266
266
  "examples": [
267
267
  {
268
- "description": "Open Perps through the stable alias",
268
+ "description": "Ask the adapter to open the current Perps entry point",
269
269
  "node": {
270
270
  "action": "ui.navigate",
271
271
  "page": "perps",
@@ -273,7 +273,7 @@
273
273
  }
274
274
  },
275
275
  {
276
- "description": "Open a Perps market through the stable alias",
276
+ "description": "Open a Perps market through the current verified adapter path",
277
277
  "node": {
278
278
  "action": "ui.navigate",
279
279
  "page": "perps-market",
@@ -282,7 +282,7 @@
282
282
  }
283
283
  },
284
284
  {
285
- "description": "Fallback to a raw React Navigation route when no alias exists",
285
+ "description": "Use a raw React Navigation route only after verifying it in the current app",
286
286
  "node": {
287
287
  "action": "ui.navigate",
288
288
  "route": "PerpsMarketListView",
@@ -316,6 +316,10 @@
316
316
  },
317
317
  "settle": {
318
318
  "type": "boolean"
319
+ },
320
+ "long_press": {
321
+ "type": "boolean",
322
+ "description": "Invoke the target component's long-press gesture. Requires identifier targeting."
319
323
  }
320
324
  },
321
325
  "additionalProperties": false
@@ -336,6 +340,15 @@
336
340
  "text": "Ethereum",
337
341
  "intent": "Press the component containing the visible Ethereum label"
338
342
  }
343
+ },
344
+ {
345
+ "description": "Long-press a component by stable React Native testID",
346
+ "node": {
347
+ "action": "ui.press",
348
+ "test_id": "keypad-delete-button",
349
+ "long_press": true,
350
+ "intent": "Clear the current keypad value through its human reset gesture"
351
+ }
339
352
  }
340
353
  ]
341
354
  },
@@ -1730,17 +1743,23 @@
1730
1743
  "long",
1731
1744
  "short"
1732
1745
  ],
1733
- "description": "Optional position/order side filter."
1746
+ "description": "Required order direction."
1734
1747
  },
1735
1748
  "timeout_ms": {
1736
1749
  "type": "number"
1737
1750
  },
1738
1751
  "amount": {
1739
- "type": "string",
1752
+ "type": [
1753
+ "string",
1754
+ "number"
1755
+ ],
1740
1756
  "description": "USD amount/notional alias."
1741
1757
  },
1742
1758
  "notional": {
1743
- "type": "string",
1759
+ "type": [
1760
+ "string",
1761
+ "number"
1762
+ ],
1744
1763
  "description": "USD notional alias."
1745
1764
  },
1746
1765
  "size": {
@@ -2091,11 +2110,25 @@
2091
2110
  "long",
2092
2111
  "short"
2093
2112
  ],
2094
- "description": "Optional position/order side filter."
2113
+ "description": "Required when state=open/present; otherwise filters selected positions."
2095
2114
  },
2096
2115
  "timeout_ms": {
2097
2116
  "type": "number"
2098
2117
  },
2118
+ "amount": {
2119
+ "type": [
2120
+ "string",
2121
+ "number"
2122
+ ],
2123
+ "description": "Explicit USD notional used only when creating a missing open position. Alias: notional."
2124
+ },
2125
+ "notional": {
2126
+ "type": [
2127
+ "string",
2128
+ "number"
2129
+ ],
2130
+ "description": "Alias for amount."
2131
+ },
2099
2132
  "state": {
2100
2133
  "type": "string",
2101
2134
  "enum": [
@@ -2131,6 +2164,17 @@
2131
2164
  "mode": "all",
2132
2165
  "intent": "Converge Perps positions to the requested state"
2133
2166
  }
2167
+ },
2168
+ {
2169
+ "description": "Ensure one ETH long position exists",
2170
+ "node": {
2171
+ "action": "metamask.perps.ensure_positions",
2172
+ "market": "ETH",
2173
+ "side": "long",
2174
+ "state": "open",
2175
+ "notional": "10",
2176
+ "intent": "Converge ETH positions to one explicit testnet precondition"
2177
+ }
2134
2178
  }
2135
2179
  ],
2136
2180
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
@@ -2143,7 +2187,7 @@
2143
2187
  {
2144
2188
  "name": "metamask.perps.ensure_orders",
2145
2189
  "owner": "metamask",
2146
- "description": "mobile Default to testnet for Perps mutations; mainnet is read-only unless explicitly requested. Higher-level wrapper that reads selected orders, cancels when needed, then asserts final order state.",
2190
+ "description": "mobile Converge selected testnet orders to open or absent, then independently assert the final state. Creating an open state uses a resting limit order.",
2147
2191
  "schema": {
2148
2192
  "type": "object",
2149
2193
  "properties": {
@@ -2221,11 +2265,30 @@
2221
2265
  "long",
2222
2266
  "short"
2223
2267
  ],
2224
- "description": "Optional position/order side filter."
2268
+ "description": "Required when state=open/present; otherwise filters selected orders."
2225
2269
  },
2226
2270
  "timeout_ms": {
2227
2271
  "type": "number"
2228
2272
  },
2273
+ "amount": {
2274
+ "type": [
2275
+ "string",
2276
+ "number"
2277
+ ],
2278
+ "description": "Explicit USD notional used only when creating a missing open order. Alias: notional."
2279
+ },
2280
+ "notional": {
2281
+ "type": [
2282
+ "string",
2283
+ "number"
2284
+ ],
2285
+ "description": "Alias for amount."
2286
+ },
2287
+ "leverage": {
2288
+ "type": "number",
2289
+ "default": 3,
2290
+ "description": "Testnet leverage used only when creating a missing open order."
2291
+ },
2229
2292
  "state": {
2230
2293
  "type": "string",
2231
2294
  "enum": [
@@ -2252,6 +2315,18 @@
2252
2315
  "mode": "all",
2253
2316
  "intent": "Converge Perps orders to the requested state"
2254
2317
  }
2318
+ },
2319
+ {
2320
+ "description": "Ensure one small resting ETH short order exists",
2321
+ "node": {
2322
+ "action": "metamask.perps.ensure_orders",
2323
+ "market": "ETH",
2324
+ "side": "short",
2325
+ "state": "open",
2326
+ "notional": 10,
2327
+ "leverage": 2,
2328
+ "intent": "Converge ETH open orders to one deterministic testnet precondition"
2329
+ }
2255
2330
  }
2256
2331
  ],
2257
2332
  "proof_effect": "E2E validation must record this action in trace.json; live-proof actions include liveAdapter/proofPath or target runtime output.",
@@ -40,20 +40,14 @@
40
40
  "action": "ui.navigate",
41
41
  "intent": "Show the Perps home surface",
42
42
  "next": "navigate-market",
43
- "route": "PerpsMarketListView",
44
- "hash": "#/?tab=perps"
43
+ "page": "perps"
45
44
  },
46
45
  "navigate-market": {
47
46
  "action": "ui.navigate",
48
47
  "intent": "Show the ETH Perps market details",
49
48
  "next": "start-state",
50
- "route": "PerpsMarketDetails",
51
- "params": {
52
- "market": {
53
- "symbol": "ETH"
54
- }
55
- },
56
- "hash": "#/perps/market/ETH"
49
+ "page": "perps-market",
50
+ "market": "ETH"
57
51
  },
58
52
  "start-state": {
59
53
  "action": "metamask.perps.start_state",
@@ -116,7 +116,7 @@
116
116
  "action": "ui.navigate",
117
117
  "next": "ui-wait-perps",
118
118
  "intent": "Open the Perps tab",
119
- "hash": "#/?tab=perps"
119
+ "page": "perps"
120
120
  },
121
121
  "ui-wait-perps": {
122
122
  "action": "ui.wait_for",
@@ -148,19 +148,20 @@
148
148
  "action": "ui.navigate",
149
149
  "next": "perps-navigate-home",
150
150
  "intent": "Show the Perps home surface",
151
- "hash": "#/?tab=perps"
151
+ "page": "perps"
152
152
  },
153
153
  "perps-navigate-home": {
154
154
  "action": "ui.navigate",
155
155
  "next": "perps-navigate-market",
156
156
  "intent": "Show the Perps home surface",
157
- "hash": "#/?tab=perps"
157
+ "page": "perps"
158
158
  },
159
159
  "perps-navigate-market": {
160
160
  "action": "ui.navigate",
161
161
  "next": "start-state",
162
162
  "intent": "Show the ETH Perps market details",
163
- "hash": "#/perps/market/ETH"
163
+ "page": "perps-market",
164
+ "market": "ETH"
164
165
  },
165
166
  "ensure-clean": {
166
167
  "action": "metamask.perps.ensure_positions",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"
@@ -19,9 +19,10 @@
19
19
  "check:syntax": "find . -name '*.mjs' -print0 | xargs -0 -n1 node --check"
20
20
  },
21
21
  "dependencies": {
22
- "@farmslot/agent-runtime": "^0.2.0",
23
- "@farmslot/protocol": "^0.11.0",
24
- "@farmslot/recipe-harness": "^0.9.0",
22
+ "@farmslot/agent-runtime": "^0.3.0",
23
+ "@farmslot/handoff": "^0.3.1",
24
+ "@farmslot/protocol": "^0.11.1",
25
+ "@farmslot/recipe-harness": "^0.9.4",
25
26
  "commander": "^12.0.0",
26
27
  "es-module-lexer": "2.3.1",
27
28
  "esbuild": "0.28.1",
@@ -77,7 +77,7 @@ if [ -n "${BASH_VERSION:-}" ]; then
77
77
  case "$cmd" in
78
78
  launch) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "ios android" -- "$cur")) ;;
79
79
  fixtures) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "init sync set generate finalize" -- "$cur")) ;;
80
- checklist) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "mark" -- "$cur")) ;;
80
+ checklist) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "mark closeout" -- "$cur")) ;;
81
81
  completions) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "install bash zsh status" -- "$cur")) ;;
82
82
  call) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "$(_mmh_actions)" -- "$cur")) ;;
83
83
  run) COMPREPLY=($(compgen -f -- "$cur"; compgen -W "$(_mmh_recipes)" -- "$cur")) ;;
@@ -111,7 +111,7 @@ if [ -n "${ZSH_VERSION:-}" ]; then
111
111
  case "$cmd" in
112
112
  launch) (( CURRENT == 3 )) && { candidates=(ios android); compadd -a candidates; } ;;
113
113
  fixtures) (( CURRENT == 3 )) && { candidates=(init sync set generate finalize); compadd -a candidates; } ;;
114
- checklist) (( CURRENT == 3 )) && { candidates=(mark); compadd -a candidates; } ;;
114
+ checklist) (( CURRENT == 3 )) && { candidates=(mark closeout); compadd -a candidates; } ;;
115
115
  completions) (( CURRENT == 3 )) && { candidates=(install bash zsh status); compadd -a candidates; } ;;
116
116
  call) (( CURRENT == 3 )) && { candidates=("${(@f)$(_mmh_actions)}"); compadd -a candidates; } ;;
117
117
  run) candidates=("${(@f)$(_mmh_recipes)}"); compadd -a candidates; _files ;;