@deeeed/metamask-harness 0.12.0 → 0.14.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 (90) hide show
  1. package/CHANGELOG.md +26 -5
  2. package/adapters/core/cleanup.sh +0 -0
  3. package/adapters/core/inject.sh +0 -0
  4. package/adapters/extension/cleanup.mjs +0 -0
  5. package/adapters/extension/ensure-browser.sh +0 -0
  6. package/adapters/extension/inject.mjs +0 -0
  7. package/adapters/extension/launch-browser.cjs +0 -0
  8. package/adapters/extension/launch.sh +0 -0
  9. package/adapters/extension/live.sh +0 -0
  10. package/adapters/extension/readiness.mjs +0 -0
  11. package/adapters/extension/reattach.sh +0 -0
  12. package/adapters/extension/refresh-build.sh +0 -0
  13. package/adapters/extension/seed-fixture.sh +0 -0
  14. package/adapters/extension/sidepanel-toggle.sh +0 -0
  15. package/adapters/extension/snapshot-dist.sh +0 -0
  16. package/adapters/extension/start-watch.sh +0 -0
  17. package/adapters/extension/verify.sh +4 -4
  18. package/adapters/extension/wallet-fixture-state.cjs +0 -0
  19. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +16 -0
  20. package/adapters/mobile/bridge-runtime/console-forwarder.cjs +2 -4
  21. package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +106 -0
  22. package/adapters/mobile/bridge-runtime/lib/console-format.cjs +53 -0
  23. package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +82 -0
  24. package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +17 -13
  25. package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +10 -5
  26. package/adapters/mobile/bridge-runtime/setup-wallet.sh +0 -0
  27. package/adapters/mobile/cleanup.sh +0 -0
  28. package/adapters/mobile/inject.sh +0 -0
  29. package/adapters/mobile/lib/metro-listener.sh +0 -0
  30. package/adapters/mobile/lib/tmux-viewer.sh +0 -0
  31. package/adapters/mobile/open-device.sh +0 -0
  32. package/adapters/mobile/prewarm-bundle.sh +0 -0
  33. package/adapters/mobile/start-metro.sh +22 -1
  34. package/adapters/mobile/stop-metro.sh +0 -0
  35. package/adapters/mobile/verify.sh +50 -13
  36. package/adapters/mobile/wait-for-bridge.sh +41 -23
  37. package/adapters/mobile/yarn-setup.sh +0 -0
  38. package/adapters/shared/activate-repo-node.sh +0 -0
  39. package/adapters/shared/activate-repo-ruby.sh +0 -0
  40. package/adapters/shared/cli-ux.sh +0 -0
  41. package/adapters/shared/ensure-runner-deps.sh +0 -0
  42. package/adapters/shared/harness-path.sh +0 -0
  43. package/adapters/shared/hash-helpers.sh +0 -0
  44. package/adapters/shared/json-field.sh +0 -0
  45. package/adapters/shared/log-tui.mjs +7 -3
  46. package/adapters/shared/open-log-window.sh +0 -0
  47. package/adapters/shared/reap-checkout-metros.sh +0 -0
  48. package/adapters/shared/resolve-farmslot-ports.mjs +0 -0
  49. package/adapters/shared/resolve-farmslot-ports.sh +0 -0
  50. package/adapters/shared/resolve-slot-ports.mjs +0 -0
  51. package/adapters/shared/resolve-slot-ports.sh +0 -0
  52. package/adapters/shared/sync-wallet-fixture.sh +0 -0
  53. package/adapters/shared/tmux-session.sh +0 -0
  54. package/dist/adapters/mobile/prepare.js +23 -2
  55. package/dist/adapters/mobile/runtime-decision.js +2 -1
  56. package/dist/adapters.js +33 -10
  57. package/dist/cli-commands.js +5 -4
  58. package/dist/commands/call.js +138 -3
  59. package/dist/commands/device-target.js +10 -3
  60. package/dist/commands/fixtures.js +2 -1
  61. package/dist/commands/manifest.js +2 -0
  62. package/dist/commands/run-engine.js +71 -4
  63. package/dist/commands/run.js +2 -0
  64. package/dist/commands/self-test.js +1 -1
  65. package/dist/commands/status.js +19 -4
  66. package/dist/mm-harness-cli.js +19 -5
  67. package/dist/recipe-files.js +14 -0
  68. package/docs/architecture.md +2 -2
  69. package/docs/live-adapter-contract.md +1 -1
  70. package/docs/recipe-libraries.md +21 -18
  71. package/library/actions/mobile/platform/bridge.mjs +35 -4
  72. package/library/recipes/{app-lifecycle-android-smoke.mobile.recipe.json → app/lifecycle.android-smoke.mobile.recipe.json} +1 -1
  73. package/library/recipes/{perps-performance.mobile.recipe.json → perps/performance.mobile.recipe.json} +1 -1
  74. package/library/recipes/perps/smoke.core.recipe.json +39 -0
  75. package/library/recipes/perps/smoke.extension.recipe.json +51 -0
  76. package/library/recipes/perps/smoke.mobile.recipe.json +51 -0
  77. package/library/recipes/{action-validation.extension.recipe.json → runner/action-validation.extension.recipe.json} +7 -7
  78. package/library/recipes/{action-validation.mobile.recipe.json → runner/action-validation.mobile.recipe.json} +7 -7
  79. package/package.json +2 -2
  80. package/scripts/completions.sh +0 -0
  81. package/scripts/install-completions.sh +0 -0
  82. /package/library/recipes/{perps-lifecycle.recipe.json → perps/lifecycle.recipe.json} +0 -0
  83. /package/library/recipes/{order-lifecycle.core.recipe.json → perps/order-lifecycle.core.recipe.json} +0 -0
  84. /package/library/recipes/{perps-performance-background-resume.mobile.recipe.json → perps/performance.background-resume.mobile.recipe.json} +0 -0
  85. /package/library/recipes/{perps-performance-cold-start.mobile.recipe.json → perps/performance.cold-start.mobile.recipe.json} +0 -0
  86. /package/library/recipes/{perps-performance-warm-start.mobile.recipe.json → perps/performance.warm-start.mobile.recipe.json} +0 -0
  87. /package/library/recipes/{read-markets.core.recipe.json → perps/read-markets.core.recipe.json} +0 -0
  88. /package/library/recipes/{trading-lifecycle.core.recipe.json → perps/trading-lifecycle.core.recipe.json} +0 -0
  89. /package/library/recipes/{smoke.extension.recipe.json → runner/smoke.extension.recipe.json} +0 -0
  90. /package/library/recipes/{smoke.mobile.recipe.json → runner/smoke.mobile.recipe.json} +0 -0
@@ -3,9 +3,35 @@ import { execFile, spawn } from 'node:child_process';
3
3
  import { promisify } from 'node:util';
4
4
  import path from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
+ import bridgeErrors from '../../../../adapters/mobile/bridge-runtime/lib/bridge-errors.cjs';
7
+
8
+ const {
9
+ BRIDGE_ERROR_CODES,
10
+ ERROR_CODE_BY_EXIT_CODE,
11
+ classifyBridgeErrorMessage,
12
+ coded,
13
+ parseErrorMarker,
14
+ } = bridgeErrors;
15
+
16
+ // Re-exported so the TS adapter classifies on the same code constants without a
17
+ // second import path into the cjs bridge-runtime.
18
+ export const MOBILE_BRIDGE_ERROR_CODES = BRIDGE_ERROR_CODES;
6
19
 
7
20
  const execFileAsync = promisify(execFile);
8
21
 
22
+ // Recover the typed code a cdp-bridge child reported: the stderr marker is
23
+ // authoritative (it carries the class the bridge classified at the source), the
24
+ // coded exit status is the fallback for output-less failures, and a raw message
25
+ // needle covers a bridge that predates the codes.
26
+ function bridgeChildErrorCode(exitCode, output) {
27
+ return (
28
+ parseErrorMarker(output) ||
29
+ ERROR_CODE_BY_EXIT_CODE[exitCode] ||
30
+ classifyBridgeErrorMessage(output) ||
31
+ null
32
+ );
33
+ }
34
+
9
35
  function sleep(ms) {
10
36
  return new Promise((resolve) => setTimeout(resolve, ms));
11
37
  }
@@ -169,12 +195,12 @@ export function selectBridgeStatusEntry(status, input) {
169
195
  }
170
196
  // Pinned android but no android entry answered — failing fast beats letting the
171
197
  // caller read the iOS entry and report misleading wallet state.
172
- throw new Error(
198
+ throw coded(new Error(
173
199
  `Pinned android device ${adbSerial} has no responding bridge target.\n` +
174
200
  ` Bridge status entries:\n` +
175
201
  entries.map((entry) => ` - ${entry.deviceName ?? '?'} [${entry.platform || 'unknown'}]`).join('\n') +
176
202
  `\n Next: mm-harness launch android # bring the app back to the foreground`,
177
- );
203
+ ), BRIDGE_ERROR_CODES.NO_TARGET);
178
204
  }
179
205
  if (iosSimulator) {
180
206
  const sim = entries.find((entry) => entry.deviceName === iosSimulator);
@@ -239,11 +265,16 @@ export async function bridgeCommand(input, args) {
239
265
  });
240
266
  if (result.timedOut) {
241
267
  const command = ['node', path.relative(input.context.projectRoot, script), ...redactBridgeArgs(args)].join(' ');
242
- throw new Error(`Mobile CDP bridge command timed out after ${result.timeoutMs}ms: ${command}`);
268
+ throw coded(
269
+ new Error(`Mobile CDP bridge command timed out after ${result.timeoutMs}ms: ${command}`),
270
+ BRIDGE_ERROR_CODES.CDP_TIMEOUT,
271
+ );
243
272
  }
244
273
  if (result.exitCode !== 0) {
245
274
  const command = ['node', path.relative(input.context.projectRoot, script), ...redactBridgeArgs(args)].join(' ');
246
- throw new Error(`Mobile CDP bridge command failed: ${command}\n${redactBridgeOutput(result.stderr || result.stdout, sensitiveBridgeArgs(args))}`);
275
+ const code = bridgeChildErrorCode(result.exitCode, result.stderr || result.stdout);
276
+ const error = new Error(`Mobile CDP bridge command failed: ${command}\n${redactBridgeOutput(result.stderr || result.stdout, sensitiveBridgeArgs(args))}`);
277
+ throw code ? coded(error, code) : error;
247
278
  }
248
279
  // For transient commands, stdout of '' or 'undefined' means the state is not yet
249
280
  // settled (e.g. mid-navigation). Return null so callers like waitForRoute can poll
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "screenshot-after": {
70
70
  "action": "ui.screenshot",
71
- "path": "screenshots/app-lifecycle-android-smoke.png",
71
+ "path": "screenshots/app.lifecycle.android-smoke.png",
72
72
  "intent": "Capture the app after Android lifecycle foreground",
73
73
  "detail": "Visual proof that the selected device is displaying the relaunched app.",
74
74
  "flow": "evidence",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": 1,
3
3
  "title": "MetaMask Mobile Perps performance flow",
4
- "description": "Canonical measured flow for MetaMask Mobile Perps: setup unlocks the wallet, startState records the stable status, then the measured workflow opens the Perps market list, reads live state, and opens a market detail. Timings live in trace.json as each node's duration; there is no built-in benchmark verb. Run pinned so numbers are comparable: `mm-harness run perps-performance --device <serial> --heal off`. Optional testnet order placement is intentionally omitted because a live order would make the flow destructive and non-repeatable; add metamask.perps.place_order + close in a personal copy when you want to measure the trade path.",
4
+ "description": "Canonical measured flow for MetaMask Mobile Perps: setup unlocks the wallet, startState records the stable status, then the measured workflow opens the Perps market list, reads live state, and opens a market detail. Timings live in trace.json as each node's duration; there is no built-in benchmark verb. Run pinned so numbers are comparable: `mm-harness run perps.performance --device <serial> --heal off`. Optional testnet order placement is intentionally omitted because a live order would make the flow destructive and non-repeatable; add metamask.perps.place_order + close in a personal copy when you want to measure the trade path.",
5
5
  "startState": {
6
6
  "action": "app.status",
7
7
  "intent": "Record the stable run start status after wallet setup",
@@ -0,0 +1,39 @@
1
+ {
2
+ "schema_version": 1,
3
+ "title": "MetaMask core Perps smoke",
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
+ }
36
+ }
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "schema_version": 1,
3
+ "title": "MetaMask Extension Perps smoke",
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
+ }
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "schema_version": 1,
3
+ "title": "MetaMask Mobile Perps smoke",
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
+ }
48
+ }
49
+ }
50
+ }
51
+ }
@@ -8,9 +8,9 @@
8
8
  "nodes": {
9
9
  "prepare-files": {
10
10
  "action": "command",
11
- "cmd": "mkdir -p temp/recipe-action-validation && printf 'E2E_ACTION_VALIDATION extension\\n' > temp/recipe-action-validation/probe.txt && printf '{\"platform\":\"extension\",\"ok\":true}\n' > temp/recipe-action-validation/probe.json && printf 'extension log E2E_ACTION_VALIDATION\\n' > temp/recipe-action-validation/validation.log && echo E2E_ACTION_VALIDATION extension",
11
+ "cmd": "mkdir -p temp/recipe-runner.action-validation && printf 'E2E_ACTION_VALIDATION extension\\n' > temp/recipe-runner.action-validation/probe.txt && printf '{\"platform\":\"extension\",\"ok\":true}\n' > temp/recipe-runner.action-validation/probe.json && printf 'extension log E2E_ACTION_VALIDATION\\n' > temp/recipe-runner.action-validation/validation.log && echo E2E_ACTION_VALIDATION extension",
12
12
  "next": "assert-command-exit",
13
- "intent": "Prepare action-validation probe files",
13
+ "intent": "Prepare runner.action-validation probe files",
14
14
  "detail": "Create local files used to prove command/assert/log/artifact actions.",
15
15
  "flow": "setup"
16
16
  },
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "assert-file": {
37
37
  "action": "assert_file",
38
- "path": "temp/recipe-action-validation/probe.txt",
38
+ "path": "temp/recipe-runner.action-validation/probe.txt",
39
39
  "contains": "E2E_ACTION_VALIDATION extension",
40
40
  "next": "assert-json",
41
41
  "intent": "Verify file assertions work",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "assert-json": {
46
46
  "action": "assert_json",
47
- "path": "temp/recipe-action-validation/probe.json",
47
+ "path": "temp/recipe-runner.action-validation/probe.json",
48
48
  "assert": {
49
49
  "path": "$.platform",
50
50
  "operator": "eq",
@@ -57,7 +57,7 @@
57
57
  },
58
58
  "watch-logs": {
59
59
  "action": "watch_logs",
60
- "path": "temp/recipe-action-validation/validation.log",
60
+ "path": "temp/recipe-runner.action-validation/validation.log",
61
61
  "contains": "E2E_ACTION_VALIDATION",
62
62
  "next": "index-artifacts",
63
63
  "intent": "Verify log watching works",
@@ -68,7 +68,7 @@
68
68
  "action": "index_artifacts",
69
69
  "artifacts": [
70
70
  {
71
- "path": "temp/recipe-action-validation/probe.txt",
71
+ "path": "temp/recipe-runner.action-validation/probe.txt",
72
72
  "type": "log",
73
73
  "category": "debug",
74
74
  "label": "Extension action validation probe"
@@ -173,7 +173,7 @@
173
173
  },
174
174
  "ui-screenshot-perps": {
175
175
  "action": "ui.screenshot",
176
- "path": "screenshots/extension-perps-action-validation.png",
176
+ "path": "screenshots/extension-perps-runner.action-validation.png",
177
177
  "timeout_ms": 5000,
178
178
  "next": "wallet-navigate-perps",
179
179
  "intent": "Capture Perps visual proof",
@@ -8,9 +8,9 @@
8
8
  "nodes": {
9
9
  "prepare-files": {
10
10
  "action": "command",
11
- "cmd": "mkdir -p temp/recipe-action-validation && printf 'E2E_ACTION_VALIDATION mobile\\n' > temp/recipe-action-validation/probe.txt && printf '{\"platform\":\"mobile\",\"ok\":true}\n' > temp/recipe-action-validation/probe.json && printf 'mobile log E2E_ACTION_VALIDATION\\n' > temp/recipe-action-validation/validation.log && echo E2E_ACTION_VALIDATION mobile",
11
+ "cmd": "mkdir -p temp/recipe-runner.action-validation && printf 'E2E_ACTION_VALIDATION mobile\\n' > temp/recipe-runner.action-validation/probe.txt && printf '{\"platform\":\"mobile\",\"ok\":true}\n' > temp/recipe-runner.action-validation/probe.json && printf 'mobile log E2E_ACTION_VALIDATION\\n' > temp/recipe-runner.action-validation/validation.log && echo E2E_ACTION_VALIDATION mobile",
12
12
  "next": "assert-command-exit",
13
- "intent": "Prepare action-validation probe files",
13
+ "intent": "Prepare runner.action-validation probe files",
14
14
  "detail": "Create local files used to prove command/assert/log/artifact actions.",
15
15
  "flow": "setup"
16
16
  },
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "assert-file": {
37
37
  "action": "assert_file",
38
- "path": "temp/recipe-action-validation/probe.txt",
38
+ "path": "temp/recipe-runner.action-validation/probe.txt",
39
39
  "contains": "E2E_ACTION_VALIDATION mobile",
40
40
  "next": "assert-json",
41
41
  "intent": "Verify file assertions work",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "assert-json": {
46
46
  "action": "assert_json",
47
- "path": "temp/recipe-action-validation/probe.json",
47
+ "path": "temp/recipe-runner.action-validation/probe.json",
48
48
  "assert": {
49
49
  "path": "$.platform",
50
50
  "operator": "eq",
@@ -57,7 +57,7 @@
57
57
  },
58
58
  "watch-logs": {
59
59
  "action": "watch_logs",
60
- "path": "temp/recipe-action-validation/validation.log",
60
+ "path": "temp/recipe-runner.action-validation/validation.log",
61
61
  "contains": "E2E_ACTION_VALIDATION",
62
62
  "next": "index-artifacts",
63
63
  "intent": "Verify log watching works",
@@ -68,7 +68,7 @@
68
68
  "action": "index_artifacts",
69
69
  "artifacts": [
70
70
  {
71
- "path": "temp/recipe-action-validation/probe.txt",
71
+ "path": "temp/recipe-runner.action-validation/probe.txt",
72
72
  "type": "log",
73
73
  "category": "debug",
74
74
  "label": "Mobile action validation probe"
@@ -174,7 +174,7 @@
174
174
  },
175
175
  "ui-screenshot-wallet": {
176
176
  "action": "ui.screenshot",
177
- "path": "screenshots/mobile-wallet-action-validation.png",
177
+ "path": "screenshots/mobile-wallet-runner.action-validation.png",
178
178
  "next": "wallet-navigate-perps",
179
179
  "intent": "Capture wallet visual proof",
180
180
  "detail": "Save a screenshot artifact after generic UI actions.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deeeed/metamask-harness",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "mm-harness": "bin/mm-harness"
@@ -69,4 +69,4 @@
69
69
  "url": "https://github.com/MetaMask/experimental-metamask-harness/issues"
70
70
  },
71
71
  "homepage": "https://github.com/MetaMask/experimental-metamask-harness#readme"
72
- }
72
+ }
File without changes
File without changes