@deeeed/metamask-harness 0.18.0 → 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 (79) hide show
  1. package/CHANGELOG.md +187 -0
  2. package/README.md +4 -7
  3. package/adapters/core/inject.sh +1 -6
  4. package/adapters/extension/inject.mjs +1 -4
  5. package/adapters/extension/verify.sh +1 -1
  6. package/adapters/mobile/inject.sh +5 -4
  7. package/adapters/mobile/verify.sh +15 -19
  8. package/adapters/shared/harness-source-fingerprint.mjs +14 -12
  9. package/dist/adapters/harness-freshness.js +49 -0
  10. package/dist/cli.js +0 -4
  11. package/dist/command-contract.js +51 -40
  12. package/dist/command-journal.js +50 -12
  13. package/dist/commands/call.js +95 -20
  14. package/dist/commands/check.js +1 -1
  15. package/dist/commands/completion-candidates.js +7 -19
  16. package/dist/commands/fixtures.js +50 -1
  17. package/dist/commands/last.js +9 -1
  18. package/dist/commands/launch/extension.js +2 -2
  19. package/dist/commands/launch/mobile.js +2 -0
  20. package/dist/commands/list-executables.js +56 -20
  21. package/dist/commands/manifest.js +28 -12
  22. package/dist/commands/parse-args.js +55 -3
  23. package/dist/commands/provision.js +0 -1
  24. package/dist/commands/run-engine.js +514 -336
  25. package/dist/commands/run.js +25 -37
  26. package/dist/commands/shared.js +1 -1
  27. package/dist/heal-bounds.js +5 -0
  28. package/dist/mm-harness-cli.js +22 -30
  29. package/dist/run-diagnostics.js +1 -1
  30. package/dist/run-recording.js +1 -1
  31. package/dist/runner.js +24 -2
  32. package/docs/CONTRIBUTING.md +2 -3
  33. package/docs/QA.md +0 -1
  34. package/docs/RECIPES.md +52 -91
  35. package/library/README.md +5 -5
  36. package/library/actions/core/perps/_controller.mjs +33 -1
  37. package/library/actions/core/perps/assert_orders.mjs +6 -7
  38. package/library/actions/core/perps/assert_positions.mjs +6 -7
  39. package/library/actions/core/perps/close_orders.mjs +2 -0
  40. package/library/actions/core/perps/close_positions.mjs +2 -0
  41. package/library/actions/core/perps/ensure_orders.mjs +4 -2
  42. package/library/actions/core/perps/ensure_positions.mjs +4 -2
  43. package/library/actions/core/perps/place_order.mjs +7 -3
  44. package/library/actions/extension/perps/assert_orders.mjs +2 -1
  45. package/library/actions/extension/perps/assert_positions.mjs +2 -1
  46. package/library/actions/extension/perps/perps.mjs +43 -14
  47. package/library/actions/mobile/perps/assert_orders.mjs +2 -1
  48. package/library/actions/mobile/perps/assert_positions.mjs +2 -1
  49. package/library/actions/mobile/perps/perps.mjs +40 -12
  50. package/library/library.json +1 -1
  51. package/library/manifests/core.action-manifest.json +1170 -413
  52. package/library/manifests/extension.action-manifest.json +1495 -641
  53. package/library/manifests/mobile.action-manifest.json +1704 -769
  54. package/library/recipes/app/lifecycle.android-smoke.mobile.recipe.json +63 -81
  55. package/library/recipes/perps/clean-market-testnet.core.recipe.json +44 -0
  56. package/library/recipes/perps/clean-market-testnet.recipe.json +49 -0
  57. package/library/recipes/perps/lifecycle.recipe.json +136 -180
  58. package/library/recipes/perps/order-lifecycle.core.recipe.json +71 -67
  59. package/library/recipes/perps/performance.background-resume.mobile.recipe.json +51 -67
  60. package/library/recipes/perps/performance.cold-start.mobile.recipe.json +51 -67
  61. package/library/recipes/perps/performance.mobile.recipe.json +37 -51
  62. package/library/recipes/perps/performance.warm-start.mobile.recipe.json +44 -59
  63. package/library/recipes/perps/read-markets.core.recipe.json +29 -31
  64. package/library/recipes/perps/smoke.core.recipe.json +29 -32
  65. package/library/recipes/perps/smoke.extension.recipe.json +41 -44
  66. package/library/recipes/perps/smoke.mobile.recipe.json +42 -44
  67. package/library/recipes/perps/trading-lifecycle.core.recipe.json +69 -65
  68. package/library/recipes/runner/action-validation.extension.recipe.json +312 -405
  69. package/library/recipes/runner/action-validation.mobile.recipe.json +316 -409
  70. package/library/recipes/runner/smoke.core.recipe.json +18 -20
  71. package/library/recipes/runner/smoke.extension.recipe.json +23 -24
  72. package/library/recipes/runner/smoke.mobile.recipe.json +23 -24
  73. package/library/recipes/wallet/smoke.extension.recipe.json +33 -35
  74. package/library/recipes/wallet/smoke.mobile.recipe.json +33 -35
  75. package/package.json +3 -3
  76. package/scripts/completions.sh +1 -4
  77. package/dist/adapters/extension/harness-freshness.js +0 -39
  78. package/dist/commands/flows.js +0 -91
  79. package/library/flows/perps.flows.json +0 -64
@@ -1,37 +1,35 @@
1
1
  {
2
- "schema_version": 1,
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "MetaMask core headless Perps read",
4
4
  "description": "Proves the headless `core` adapter instantiates @metamask/perps-controller against a resolved MetaMask/core checkout and reads live HyperLiquid testnet Perps state (positions, open orders, account state) over HTTP — no CDP, bridge, or UI.",
5
- "validate": {
6
- "workflow": {
7
- "entry": "status",
8
- "nodes": {
9
- "status": {
10
- "action": "app.status",
11
- "next": "read_positions",
12
- "intent": "Resolve the core checkout and report headless compatibility mode"
13
- },
14
- "read_positions": {
15
- "action": "metamask.perps.read_positions",
16
- "mode": "all",
17
- "next": "read_orders",
18
- "intent": "Read live Perps positions from the headless controller"
19
- },
20
- "read_orders": {
21
- "action": "metamask.perps.read_orders",
22
- "mode": "all",
23
- "next": "read_account",
24
- "intent": "Read live Perps open orders from the headless controller"
25
- },
26
- "read_account": {
27
- "action": "metamask.perps.read_account",
28
- "next": "done",
29
- "intent": "Read live Perps account state from the headless controller"
30
- },
31
- "done": {
32
- "action": "end",
33
- "status": "pass"
34
- }
5
+ "workflow": {
6
+ "entry": "status",
7
+ "nodes": {
8
+ "status": {
9
+ "action": "app.status",
10
+ "next": "read_positions",
11
+ "intent": "Resolve the core checkout and report headless compatibility mode"
12
+ },
13
+ "read_positions": {
14
+ "action": "metamask.perps.read_positions",
15
+ "mode": "all",
16
+ "next": "read_orders",
17
+ "intent": "Read live Perps positions from the headless controller"
18
+ },
19
+ "read_orders": {
20
+ "action": "metamask.perps.read_orders",
21
+ "mode": "all",
22
+ "next": "read_account",
23
+ "intent": "Read live Perps open orders from the headless controller"
24
+ },
25
+ "read_account": {
26
+ "action": "metamask.perps.read_account",
27
+ "next": "done",
28
+ "intent": "Read live Perps account state from the headless controller"
29
+ },
30
+ "done": {
31
+ "action": "end",
32
+ "status": "pass"
35
33
  }
36
34
  }
37
35
  }
@@ -1,38 +1,35 @@
1
1
  {
2
- "schema_version": 1,
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "MetaMask core Perps smoke",
4
4
  "description": "Non-mutating Perps domain smoke for the headless core adapter: instantiates the Perps controller and reads live positions, orders, and account state.",
5
- "validate": {
6
- "workflow": {
7
- "entry": "status",
8
- "nodes": {
9
- "status": {
10
- "action": "app.status",
11
- "next": "read-positions",
12
- "intent": "Resolve the core checkout and report headless compatibility mode"
13
- },
14
- "read-positions": {
15
- "action": "metamask.perps.read_positions",
16
- "mode": "all",
17
- "next": "read-orders",
18
- "intent": "Read live Perps positions from the headless controller"
19
- },
20
- "read-orders": {
21
- "action": "metamask.perps.read_orders",
22
- "mode": "all",
23
- "next": "read-account",
24
- "intent": "Read live Perps open orders from the headless controller"
25
- },
26
- "read-account": {
27
- "action": "metamask.perps.read_account",
28
- "next": "done",
29
- "intent": "Read live Perps account state from the headless controller"
30
- },
31
- "done": {
32
- "action": "end",
33
- "status": "pass",
34
- "intent": "Finish the core Perps smoke"
35
- }
5
+ "workflow": {
6
+ "entry": "status",
7
+ "nodes": {
8
+ "status": {
9
+ "action": "app.status",
10
+ "next": "read-positions",
11
+ "intent": "Resolve the core checkout and report headless compatibility mode"
12
+ },
13
+ "read-positions": {
14
+ "action": "metamask.perps.read_positions",
15
+ "mode": "all",
16
+ "next": "read-orders",
17
+ "intent": "Read live Perps positions from the headless controller"
18
+ },
19
+ "read-orders": {
20
+ "action": "metamask.perps.read_orders",
21
+ "mode": "all",
22
+ "next": "read-account",
23
+ "intent": "Read live Perps open orders from the headless controller"
24
+ },
25
+ "read-account": {
26
+ "action": "metamask.perps.read_account",
27
+ "next": "done",
28
+ "intent": "Read live Perps account state from the headless controller"
29
+ },
30
+ "done": {
31
+ "action": "end",
32
+ "status": "pass"
36
33
  }
37
34
  }
38
35
  }
@@ -1,50 +1,47 @@
1
1
  {
2
- "schema_version": 1,
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "MetaMask Extension Perps smoke",
4
4
  "description": "Non-mutating Perps domain smoke for MetaMask Extension: verifies CDP, unlocks if needed, opens the Perps page, and reads live Perps positions and orders.",
5
- "validate": {
6
- "workflow": {
7
- "entry": "status",
8
- "nodes": {
9
- "status": {
10
- "action": "app.status",
11
- "next": "cdp",
12
- "intent": "Resolve the Extension checkout and adapter status before Perps proof"
13
- },
14
- "cdp": {
15
- "action": "cdp.target",
16
- "required": true,
17
- "timeout_ms": 15000,
18
- "next": "ensure-unlocked",
19
- "intent": "Confirm the Extension CDP runtime is reachable"
20
- },
21
- "ensure-unlocked": {
22
- "action": "metamask.wallet.ensure_unlocked",
23
- "timeout_ms": 45000,
24
- "next": "open-perps",
25
- "intent": "Ensure the wallet is unlocked before opening Perps"
26
- },
27
- "open-perps": {
28
- "action": "ui.navigate",
29
- "page": "perps",
30
- "next": "read-positions",
31
- "intent": "Open the Perps page through the stable page alias"
32
- },
33
- "read-positions": {
34
- "action": "metamask.perps.read_positions",
35
- "next": "read-orders",
36
- "intent": "Read live Perps positions without mutating account state"
37
- },
38
- "read-orders": {
39
- "action": "metamask.perps.read_orders",
40
- "next": "done",
41
- "intent": "Read live Perps open orders without mutating account state"
42
- },
43
- "done": {
44
- "action": "end",
45
- "status": "pass",
46
- "intent": "Finish the Extension Perps smoke"
47
- }
5
+ "workflow": {
6
+ "entry": "status",
7
+ "nodes": {
8
+ "status": {
9
+ "action": "app.status",
10
+ "next": "cdp",
11
+ "intent": "Resolve the Extension checkout and adapter status before Perps proof"
12
+ },
13
+ "cdp": {
14
+ "action": "cdp.target",
15
+ "required": true,
16
+ "timeout_ms": 15000,
17
+ "next": "ensure-unlocked",
18
+ "intent": "Confirm the Extension CDP runtime is reachable"
19
+ },
20
+ "ensure-unlocked": {
21
+ "action": "metamask.wallet.ensure_unlocked",
22
+ "timeout_ms": 45000,
23
+ "next": "open-perps",
24
+ "intent": "Ensure the wallet is unlocked before opening Perps"
25
+ },
26
+ "open-perps": {
27
+ "action": "ui.navigate",
28
+ "page": "perps",
29
+ "next": "read-positions",
30
+ "intent": "Show the Perps home surface"
31
+ },
32
+ "read-positions": {
33
+ "action": "metamask.perps.read_positions",
34
+ "next": "read-orders",
35
+ "intent": "Read live Perps positions without mutating account state"
36
+ },
37
+ "read-orders": {
38
+ "action": "metamask.perps.read_orders",
39
+ "next": "done",
40
+ "intent": "Read live Perps open orders without mutating account state"
41
+ },
42
+ "done": {
43
+ "action": "end",
44
+ "status": "pass"
48
45
  }
49
46
  }
50
47
  }
@@ -1,50 +1,48 @@
1
1
  {
2
- "schema_version": 1,
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "MetaMask Mobile Perps smoke",
4
4
  "description": "Non-mutating Perps domain smoke for MetaMask Mobile: verifies the live bridge, unlocks if needed, opens the Perps market list, and reads live Perps positions and orders.",
5
- "validate": {
6
- "workflow": {
7
- "entry": "status",
8
- "nodes": {
9
- "status": {
10
- "action": "app.status",
11
- "next": "cdp",
12
- "intent": "Resolve the Mobile checkout and adapter status before Perps proof"
13
- },
14
- "cdp": {
15
- "action": "cdp.target",
16
- "required": true,
17
- "timeout_ms": 15000,
18
- "next": "ensure-unlocked",
19
- "intent": "Confirm the React Native debug bridge is reachable"
20
- },
21
- "ensure-unlocked": {
22
- "action": "metamask.wallet.ensure_unlocked",
23
- "timeout_ms": 45000,
24
- "next": "open-perps",
25
- "intent": "Ensure the wallet is unlocked before opening Perps"
26
- },
27
- "open-perps": {
28
- "action": "ui.navigate",
29
- "page": "perps",
30
- "next": "read-positions",
31
- "intent": "Open the Perps market list through the stable page alias"
32
- },
33
- "read-positions": {
34
- "action": "metamask.perps.read_positions",
35
- "next": "read-orders",
36
- "intent": "Read live Perps positions without mutating account state"
37
- },
38
- "read-orders": {
39
- "action": "metamask.perps.read_orders",
40
- "next": "done",
41
- "intent": "Read live Perps open orders without mutating account state"
42
- },
43
- "done": {
44
- "action": "end",
45
- "status": "pass",
46
- "intent": "Finish the Mobile Perps smoke"
47
- }
5
+ "workflow": {
6
+ "entry": "status",
7
+ "nodes": {
8
+ "status": {
9
+ "action": "app.status",
10
+ "next": "cdp",
11
+ "intent": "Resolve the Mobile checkout and adapter status before Perps proof"
12
+ },
13
+ "cdp": {
14
+ "action": "cdp.target",
15
+ "required": true,
16
+ "timeout_ms": 15000,
17
+ "next": "ensure-unlocked",
18
+ "intent": "Confirm the React Native debug bridge is reachable"
19
+ },
20
+ "ensure-unlocked": {
21
+ "action": "metamask.wallet.ensure_unlocked",
22
+ "next": "open-perps",
23
+ "intent": "Ensure the wallet is unlocked before opening Perps",
24
+ "target_timeout_ms": 45000,
25
+ "unlock_timeout_ms": 45000
26
+ },
27
+ "open-perps": {
28
+ "action": "ui.navigate",
29
+ "page": "perps",
30
+ "next": "read-positions",
31
+ "intent": "Show the Perps market list"
32
+ },
33
+ "read-positions": {
34
+ "action": "metamask.perps.read_positions",
35
+ "next": "read-orders",
36
+ "intent": "Read live Perps positions without mutating account state"
37
+ },
38
+ "read-orders": {
39
+ "action": "metamask.perps.read_orders",
40
+ "next": "done",
41
+ "intent": "Read live Perps open orders without mutating account state"
42
+ },
43
+ "done": {
44
+ "action": "end",
45
+ "status": "pass"
48
46
  }
49
47
  }
50
48
  }
@@ -1,75 +1,79 @@
1
1
  {
2
- "schema_version": 1,
2
+ "$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
3
3
  "title": "MetaMask core headless Perps trading lifecycle",
4
4
  "description": "Proves the headless `core` adapter places and closes a REAL Perps order on HyperLiquid testnet through the full signing path: a default viem signer backs the perps controller's wallet adapter, the active HyperLiquid testnet provider is initialized, and a small BTC long is opened then closed. Leaves the account FLAT. No CDP, bridge, or UI.",
5
- "validate": {
6
- "workflow": {
7
- "entry": "status",
8
- "nodes": {
9
- "status": {
10
- "action": "app.status",
11
- "next": "start_flat",
12
- "intent": "Resolve the core checkout and report headless compatibility mode"
5
+ "workflow": {
6
+ "entry": "status",
7
+ "nodes": {
8
+ "status": {
9
+ "action": "app.status",
10
+ "next": "start_flat",
11
+ "intent": "Resolve the core checkout and report headless compatibility mode"
12
+ },
13
+ "start_flat": {
14
+ "action": "metamask.perps.start_state",
15
+ "market": "BTC",
16
+ "positions": {
17
+ "state": "none"
13
18
  },
14
- "start_flat": {
15
- "action": "metamask.perps.start_state",
16
- "market": "BTC",
17
- "positions": { "state": "none" },
18
- "orders": { "state": "none" },
19
- "network": "testnet",
20
- "timeout_ms": 45000,
21
- "next": "place_order",
22
- "intent": "Converge BTC testnet baseline to flat (no positions, no orders) before the proof window"
19
+ "orders": {
20
+ "state": "none"
23
21
  },
24
- "place_order": {
25
- "action": "metamask.perps.place_order",
26
- "market": "BTC",
27
- "side": "long",
28
- "notional": "11",
29
- "leverage": 2,
30
- "network": "testnet",
31
- "timeout_ms": 45000,
32
- "next": "assert_open",
33
- "intent": "Place a small BTC long market order via the headless controller (real signed order to HL testnet)"
22
+ "network": "testnet",
23
+ "timeout_ms": 45000,
24
+ "next": "place_order",
25
+ "intent": "Converge BTC testnet baseline to flat (no positions, no orders) before the proof window"
26
+ },
27
+ "place_order": {
28
+ "action": "metamask.perps.place_order",
29
+ "market": "BTC",
30
+ "side": "long",
31
+ "notional": "11",
32
+ "leverage": 2,
33
+ "timeout_ms": 45000,
34
+ "next": "assert_open",
35
+ "intent": "Place a small BTC long market order via the headless controller (real signed order to HL testnet)"
36
+ },
37
+ "assert_open": {
38
+ "action": "metamask.perps.assert_positions",
39
+ "market": "BTC",
40
+ "state": "open",
41
+ "timeout_ms": 30000,
42
+ "next": "close_position",
43
+ "intent": "Assert the BTC position opened"
44
+ },
45
+ "close_position": {
46
+ "action": "metamask.perps.close_positions",
47
+ "market": "BTC",
48
+ "timeout_ms": 45000,
49
+ "next": "assert_flat",
50
+ "intent": "Close the BTC position via the headless controller (real signed close to HL testnet)"
51
+ },
52
+ "assert_flat": {
53
+ "action": "metamask.perps.assert_positions",
54
+ "market": "BTC",
55
+ "state": "none",
56
+ "timeout_ms": 30000,
57
+ "next": "teardown_flat",
58
+ "intent": "Assert the BTC position closed — account is flat"
59
+ },
60
+ "teardown_flat": {
61
+ "action": "metamask.perps.teardown_state",
62
+ "market": "BTC",
63
+ "positions": {
64
+ "state": "none"
34
65
  },
35
- "assert_open": {
36
- "action": "metamask.perps.assert_positions",
37
- "market": "BTC",
38
- "state": "open",
39
- "timeout_ms": 30000,
40
- "next": "close_position",
41
- "intent": "Assert the BTC position opened"
66
+ "orders": {
67
+ "state": "none"
42
68
  },
43
- "close_position": {
44
- "action": "metamask.perps.close_positions",
45
- "market": "BTC",
46
- "network": "testnet",
47
- "timeout_ms": 45000,
48
- "next": "assert_flat",
49
- "intent": "Close the BTC position via the headless controller (real signed close to HL testnet)"
50
- },
51
- "assert_flat": {
52
- "action": "metamask.perps.assert_positions",
53
- "market": "BTC",
54
- "state": "none",
55
- "timeout_ms": 30000,
56
- "next": "teardown_flat",
57
- "intent": "Assert the BTC position closed — account is flat"
58
- },
59
- "teardown_flat": {
60
- "action": "metamask.perps.teardown_state",
61
- "market": "BTC",
62
- "positions": { "state": "none" },
63
- "orders": { "state": "none" },
64
- "network": "testnet",
65
- "timeout_ms": 45000,
66
- "next": "done",
67
- "intent": "Restore BTC testnet baseline to flat after the proof (leave the shared account clean)"
68
- },
69
- "done": {
70
- "action": "end",
71
- "status": "pass"
72
- }
69
+ "network": "testnet",
70
+ "timeout_ms": 45000,
71
+ "next": "done",
72
+ "intent": "Restore BTC testnet baseline to flat after the proof (leave the shared account clean)"
73
+ },
74
+ "done": {
75
+ "action": "end",
76
+ "status": "pass"
73
77
  }
74
78
  }
75
79
  }