@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.
- package/CHANGELOG.md +187 -0
- package/README.md +4 -7
- package/adapters/core/inject.sh +1 -6
- package/adapters/extension/inject.mjs +1 -4
- package/adapters/extension/verify.sh +1 -1
- package/adapters/mobile/inject.sh +5 -4
- package/adapters/mobile/verify.sh +15 -19
- package/adapters/shared/harness-source-fingerprint.mjs +14 -12
- package/dist/adapters/harness-freshness.js +49 -0
- package/dist/cli.js +0 -4
- package/dist/command-contract.js +51 -40
- package/dist/command-journal.js +50 -12
- package/dist/commands/call.js +95 -20
- package/dist/commands/check.js +1 -1
- package/dist/commands/completion-candidates.js +7 -19
- package/dist/commands/fixtures.js +50 -1
- package/dist/commands/last.js +9 -1
- package/dist/commands/launch/extension.js +2 -2
- package/dist/commands/launch/mobile.js +2 -0
- package/dist/commands/list-executables.js +56 -20
- package/dist/commands/manifest.js +28 -12
- package/dist/commands/parse-args.js +55 -3
- package/dist/commands/provision.js +0 -1
- package/dist/commands/run-engine.js +514 -336
- package/dist/commands/run.js +25 -37
- package/dist/commands/shared.js +1 -1
- package/dist/heal-bounds.js +5 -0
- package/dist/mm-harness-cli.js +22 -30
- package/dist/run-diagnostics.js +1 -1
- package/dist/run-recording.js +1 -1
- package/dist/runner.js +24 -2
- package/docs/CONTRIBUTING.md +2 -3
- package/docs/QA.md +0 -1
- package/docs/RECIPES.md +52 -91
- package/library/README.md +5 -5
- package/library/actions/core/perps/_controller.mjs +33 -1
- package/library/actions/core/perps/assert_orders.mjs +6 -7
- package/library/actions/core/perps/assert_positions.mjs +6 -7
- package/library/actions/core/perps/close_orders.mjs +2 -0
- package/library/actions/core/perps/close_positions.mjs +2 -0
- package/library/actions/core/perps/ensure_orders.mjs +4 -2
- package/library/actions/core/perps/ensure_positions.mjs +4 -2
- package/library/actions/core/perps/place_order.mjs +7 -3
- package/library/actions/extension/perps/assert_orders.mjs +2 -1
- package/library/actions/extension/perps/assert_positions.mjs +2 -1
- package/library/actions/extension/perps/perps.mjs +43 -14
- package/library/actions/mobile/perps/assert_orders.mjs +2 -1
- package/library/actions/mobile/perps/assert_positions.mjs +2 -1
- package/library/actions/mobile/perps/perps.mjs +40 -12
- package/library/library.json +1 -1
- package/library/manifests/core.action-manifest.json +1170 -413
- package/library/manifests/extension.action-manifest.json +1495 -641
- package/library/manifests/mobile.action-manifest.json +1704 -769
- package/library/recipes/app/lifecycle.android-smoke.mobile.recipe.json +63 -81
- package/library/recipes/perps/clean-market-testnet.core.recipe.json +44 -0
- package/library/recipes/perps/clean-market-testnet.recipe.json +49 -0
- package/library/recipes/perps/lifecycle.recipe.json +136 -180
- package/library/recipes/perps/order-lifecycle.core.recipe.json +71 -67
- package/library/recipes/perps/performance.background-resume.mobile.recipe.json +51 -67
- package/library/recipes/perps/performance.cold-start.mobile.recipe.json +51 -67
- package/library/recipes/perps/performance.mobile.recipe.json +37 -51
- package/library/recipes/perps/performance.warm-start.mobile.recipe.json +44 -59
- package/library/recipes/perps/read-markets.core.recipe.json +29 -31
- package/library/recipes/perps/smoke.core.recipe.json +29 -32
- package/library/recipes/perps/smoke.extension.recipe.json +41 -44
- package/library/recipes/perps/smoke.mobile.recipe.json +42 -44
- package/library/recipes/perps/trading-lifecycle.core.recipe.json +69 -65
- package/library/recipes/runner/action-validation.extension.recipe.json +312 -405
- package/library/recipes/runner/action-validation.mobile.recipe.json +316 -409
- package/library/recipes/runner/smoke.core.recipe.json +18 -20
- package/library/recipes/runner/smoke.extension.recipe.json +23 -24
- package/library/recipes/runner/smoke.mobile.recipe.json +23 -24
- package/library/recipes/wallet/smoke.extension.recipe.json +33 -35
- package/library/recipes/wallet/smoke.mobile.recipe.json +33 -35
- package/package.json +3 -3
- package/scripts/completions.sh +1 -4
- package/dist/adapters/extension/harness-freshness.js +0 -39
- package/dist/commands/flows.js +0 -91
- package/library/flows/perps.flows.json +0 -64
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
|
|
3
3
|
"title": "MetaMask Core runner smoke",
|
|
4
4
|
"description": "Proves the headless Core runner resolves the checkout, executes generic actions, and writes a valid artifact package.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
"status": "pass"
|
|
23
|
-
}
|
|
5
|
+
"workflow": {
|
|
6
|
+
"entry": "status",
|
|
7
|
+
"nodes": {
|
|
8
|
+
"status": {
|
|
9
|
+
"action": "app.status",
|
|
10
|
+
"next": "package",
|
|
11
|
+
"intent": "Resolve the Core checkout and report headless readiness"
|
|
12
|
+
},
|
|
13
|
+
"package": {
|
|
14
|
+
"action": "assert_file",
|
|
15
|
+
"path": "package.json",
|
|
16
|
+
"next": "done",
|
|
17
|
+
"intent": "Prove generic project-file assertions work in Core"
|
|
18
|
+
},
|
|
19
|
+
"done": {
|
|
20
|
+
"action": "end",
|
|
21
|
+
"status": "pass"
|
|
24
22
|
}
|
|
25
23
|
}
|
|
26
24
|
}
|
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
|
|
3
3
|
"title": "MetaMask Extension v1 runner smoke",
|
|
4
4
|
"description": "Proves the MetaMask Extension runner executes manifest-declared actions and writes a valid artifact package.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
5
|
+
"workflow": {
|
|
6
|
+
"entry": "status",
|
|
7
|
+
"nodes": {
|
|
8
|
+
"status": {
|
|
9
|
+
"action": "app.status",
|
|
10
|
+
"next": "fixture",
|
|
11
|
+
"intent": "Confirm the Extension checkout is ready"
|
|
12
|
+
},
|
|
13
|
+
"fixture": {
|
|
14
|
+
"action": "metamask.wallet.fixture_status",
|
|
15
|
+
"next": "cdp",
|
|
16
|
+
"intent": "Confirm the wallet fixture is available"
|
|
17
|
+
},
|
|
18
|
+
"cdp": {
|
|
19
|
+
"action": "cdp.target",
|
|
20
|
+
"required": true,
|
|
21
|
+
"next": "done",
|
|
22
|
+
"intent": "Confirm the Extension runtime is reachable"
|
|
23
|
+
},
|
|
24
|
+
"done": {
|
|
25
|
+
"action": "end",
|
|
26
|
+
"status": "pass"
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
}
|
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
|
|
3
3
|
"title": "MetaMask Mobile v1 runner smoke",
|
|
4
4
|
"description": "Proves the MetaMask Mobile runner executes manifest-declared actions and writes a valid artifact package.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
5
|
+
"workflow": {
|
|
6
|
+
"entry": "status",
|
|
7
|
+
"nodes": {
|
|
8
|
+
"status": {
|
|
9
|
+
"action": "app.status",
|
|
10
|
+
"next": "fixture",
|
|
11
|
+
"intent": "Confirm the Mobile checkout is ready"
|
|
12
|
+
},
|
|
13
|
+
"fixture": {
|
|
14
|
+
"action": "metamask.wallet.fixture_status",
|
|
15
|
+
"next": "cdp",
|
|
16
|
+
"intent": "Confirm the wallet fixture is available"
|
|
17
|
+
},
|
|
18
|
+
"cdp": {
|
|
19
|
+
"action": "cdp.target",
|
|
20
|
+
"require_reachable": true,
|
|
21
|
+
"next": "done",
|
|
22
|
+
"intent": "Confirm the Mobile runtime is reachable"
|
|
23
|
+
},
|
|
24
|
+
"done": {
|
|
25
|
+
"action": "end",
|
|
26
|
+
"status": "pass"
|
|
28
27
|
}
|
|
29
28
|
}
|
|
30
29
|
}
|
|
@@ -1,41 +1,39 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
|
|
3
3
|
"title": "MetaMask Extension wallet smoke",
|
|
4
4
|
"description": "Fixture-backed proof that the Extension wallet is reachable, unlocked, readable, and visually capturable without depending on a product feature domain.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
"status": "pass"
|
|
38
|
-
}
|
|
5
|
+
"workflow": {
|
|
6
|
+
"entry": "status",
|
|
7
|
+
"nodes": {
|
|
8
|
+
"status": {
|
|
9
|
+
"action": "app.status",
|
|
10
|
+
"next": "fixture",
|
|
11
|
+
"intent": "Confirm the Extension runtime is reachable"
|
|
12
|
+
},
|
|
13
|
+
"fixture": {
|
|
14
|
+
"action": "metamask.wallet.fixture_status",
|
|
15
|
+
"next": "unlock",
|
|
16
|
+
"intent": "Confirm the checkout wallet fixture is ready"
|
|
17
|
+
},
|
|
18
|
+
"unlock": {
|
|
19
|
+
"action": "metamask.wallet.ensure_unlocked",
|
|
20
|
+
"next": "state",
|
|
21
|
+
"intent": "Ensure the fixture-backed wallet is unlocked"
|
|
22
|
+
},
|
|
23
|
+
"state": {
|
|
24
|
+
"action": "metamask.wallet.read_state",
|
|
25
|
+
"next": "screenshot",
|
|
26
|
+
"intent": "Read the current wallet state through the public adapter"
|
|
27
|
+
},
|
|
28
|
+
"screenshot": {
|
|
29
|
+
"action": "ui.screenshot",
|
|
30
|
+
"path": "screenshots/wallet-smoke.png",
|
|
31
|
+
"next": "done",
|
|
32
|
+
"intent": "Record the visible wallet state as evidence"
|
|
33
|
+
},
|
|
34
|
+
"done": {
|
|
35
|
+
"action": "end",
|
|
36
|
+
"status": "pass"
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
39
|
}
|
|
@@ -1,41 +1,39 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
|
|
3
3
|
"title": "MetaMask Mobile wallet smoke",
|
|
4
4
|
"description": "Fixture-backed proof that the Mobile wallet is reachable, unlocked, readable, and visually capturable without depending on a product feature domain.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
"status": "pass"
|
|
38
|
-
}
|
|
5
|
+
"workflow": {
|
|
6
|
+
"entry": "status",
|
|
7
|
+
"nodes": {
|
|
8
|
+
"status": {
|
|
9
|
+
"action": "app.status",
|
|
10
|
+
"next": "fixture",
|
|
11
|
+
"intent": "Confirm the Mobile runtime is reachable"
|
|
12
|
+
},
|
|
13
|
+
"fixture": {
|
|
14
|
+
"action": "metamask.wallet.fixture_status",
|
|
15
|
+
"next": "unlock",
|
|
16
|
+
"intent": "Confirm the checkout wallet fixture is ready"
|
|
17
|
+
},
|
|
18
|
+
"unlock": {
|
|
19
|
+
"action": "metamask.wallet.ensure_unlocked",
|
|
20
|
+
"next": "state",
|
|
21
|
+
"intent": "Ensure the fixture-backed wallet is unlocked"
|
|
22
|
+
},
|
|
23
|
+
"state": {
|
|
24
|
+
"action": "metamask.wallet.read_state",
|
|
25
|
+
"next": "screenshot",
|
|
26
|
+
"intent": "Read the current wallet state through the public adapter"
|
|
27
|
+
},
|
|
28
|
+
"screenshot": {
|
|
29
|
+
"action": "ui.screenshot",
|
|
30
|
+
"path": "screenshots/wallet-smoke.png",
|
|
31
|
+
"next": "done",
|
|
32
|
+
"intent": "Record the visible wallet state as evidence"
|
|
33
|
+
},
|
|
34
|
+
"done": {
|
|
35
|
+
"action": "end",
|
|
36
|
+
"status": "pass"
|
|
39
37
|
}
|
|
40
38
|
}
|
|
41
39
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeeed/metamask-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mm-harness": "bin/mm-harness"
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@farmslot/agent-runtime": "^0.2.0",
|
|
23
|
-
"@farmslot/protocol": "^0.
|
|
24
|
-
"@farmslot/recipe-harness": "^0.
|
|
23
|
+
"@farmslot/protocol": "^0.11.0",
|
|
24
|
+
"@farmslot/recipe-harness": "^0.9.0",
|
|
25
25
|
"commander": "^12.0.0",
|
|
26
26
|
"es-module-lexer": "2.3.1",
|
|
27
27
|
"esbuild": "0.28.1",
|
package/scripts/completions.sh
CHANGED
|
@@ -29,7 +29,7 @@ _mmh_bin() {
|
|
|
29
29
|
return 1
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
_mmh_commands="launch stop logs debug fixtures actions call
|
|
32
|
+
_mmh_commands="launch stop logs debug fixtures actions call run doctor check checklist recipe-quality install verify cleanup completions"
|
|
33
33
|
|
|
34
34
|
# Per-command flags (static, from the mm-harness surface).
|
|
35
35
|
_mmh_flags_for() {
|
|
@@ -42,7 +42,6 @@ _mmh_flags_for() {
|
|
|
42
42
|
checklist) printf '%s' "" ;;
|
|
43
43
|
actions) printf '%s' "--adapter --action --kind --raw --action-manifest --target --json" ;;
|
|
44
44
|
call) printf '%s' "--list --arg --adapter --target --artifacts-dir --action-manifest --heal --json" ;;
|
|
45
|
-
flows) printf '%s' "--library --json" ;;
|
|
46
45
|
run) printf '%s' "--list --describe --plan --adapter --artifacts-dir --target --library --cdp-port --heal --record-video --json" ;;
|
|
47
46
|
doctor) printf '%s' "--adapter --target --fix --json" ;;
|
|
48
47
|
install|verify|cleanup) printf '%s' "--adapter --target --json" ;;
|
|
@@ -80,7 +79,6 @@ if [ -n "${BASH_VERSION:-}" ]; then
|
|
|
80
79
|
fixtures) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "init sync set generate finalize" -- "$cur")) ;;
|
|
81
80
|
checklist) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "mark" -- "$cur")) ;;
|
|
82
81
|
completions) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "install bash zsh status" -- "$cur")) ;;
|
|
83
|
-
flows) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "list promote" -- "$cur")) ;;
|
|
84
82
|
call) [ "$cword" -eq 2 ] && COMPREPLY=($(compgen -W "$(_mmh_actions)" -- "$cur")) ;;
|
|
85
83
|
run) COMPREPLY=($(compgen -f -- "$cur"; compgen -W "$(_mmh_recipes)" -- "$cur")) ;;
|
|
86
84
|
*) COMPREPLY=($(compgen -W "$(_mmh_flags_for "$cmd")" -- "$cur")) ;;
|
|
@@ -115,7 +113,6 @@ if [ -n "${ZSH_VERSION:-}" ]; then
|
|
|
115
113
|
fixtures) (( CURRENT == 3 )) && { candidates=(init sync set generate finalize); compadd -a candidates; } ;;
|
|
116
114
|
checklist) (( CURRENT == 3 )) && { candidates=(mark); compadd -a candidates; } ;;
|
|
117
115
|
completions) (( CURRENT == 3 )) && { candidates=(install bash zsh status); compadd -a candidates; } ;;
|
|
118
|
-
flows) (( CURRENT == 3 )) && { candidates=(list promote); compadd -a candidates; } ;;
|
|
119
116
|
call) (( CURRENT == 3 )) && { candidates=("${(@f)$(_mmh_actions)}"); compadd -a candidates; } ;;
|
|
120
117
|
run) candidates=("${(@f)$(_mmh_recipes)}"); compadd -a candidates; _files ;;
|
|
121
118
|
*) candidates=(${=$(_mmh_flags_for "$cmd")}); compadd -a candidates ;;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from "node:child_process";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { pathToFileURL } from "node:url";
|
|
5
|
-
import { recipeHarnessPath, runnerDir } from "../../paths.js";
|
|
6
|
-
async function ensureExtensionHarnessFresh(target) {
|
|
7
|
-
if (!fs.existsSync(path.join(target, "package.json"))) return;
|
|
8
|
-
let current;
|
|
9
|
-
try {
|
|
10
|
-
const mod = await import(pathToFileURL(path.join(runnerDir, "adapters/shared/harness-source-fingerprint.mjs")).href);
|
|
11
|
-
current = mod.harnessSourceFingerprint(runnerDir);
|
|
12
|
-
} catch {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const manifestPath = recipeHarnessPath(target, "extension", "manifest.json");
|
|
16
|
-
const installed = readInstalledFingerprint(manifestPath);
|
|
17
|
-
if (installed === current) return;
|
|
18
|
-
const reason = installed === null ? "harness not installed" : "runner changed";
|
|
19
|
-
try {
|
|
20
|
-
execFileSync(process.execPath, [path.join(runnerDir, "adapters/extension/inject.mjs"), "--target", target], {
|
|
21
|
-
stdio: ["ignore", "ignore", "inherit"]
|
|
22
|
-
});
|
|
23
|
-
console.error(`\u2192 refreshed extension harness overlay (${reason})`);
|
|
24
|
-
} catch (error) {
|
|
25
|
-
const detail = error instanceof Error ? `: ${error.message}` : "";
|
|
26
|
-
throw new Error(`could not refresh the extension harness overlay (${reason})${detail}`);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function readInstalledFingerprint(manifestPath) {
|
|
30
|
-
try {
|
|
31
|
-
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
32
|
-
return typeof manifest.sourceFingerprint === "string" ? manifest.sourceFingerprint : null;
|
|
33
|
-
} catch {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
export {
|
|
38
|
-
ensureExtensionHarnessFresh
|
|
39
|
-
};
|
package/dist/commands/flows.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { color } from "../cli-color.js";
|
|
3
|
-
import { importRecipeHarnessCli } from "../paths.js";
|
|
4
|
-
import { EXIT } from "./shared.js";
|
|
5
|
-
import { parseArgs, usageError } from "./parse-args.js";
|
|
6
|
-
import { resolveMetaMaskLibrarySources } from "./run-engine.js";
|
|
7
|
-
const FLOWS_SUBCOMMANDS = ["list", "describe", "promote"];
|
|
8
|
-
function stripFrontOnlyFlags(argv) {
|
|
9
|
-
const out = [];
|
|
10
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
11
|
-
const arg = argv[i];
|
|
12
|
-
if (arg === "--target" || arg === "--library") {
|
|
13
|
-
i += 1;
|
|
14
|
-
continue;
|
|
15
|
-
}
|
|
16
|
-
if (arg.startsWith("--target=") || arg.startsWith("--library=")) continue;
|
|
17
|
-
out.push(arg);
|
|
18
|
-
}
|
|
19
|
-
return out;
|
|
20
|
-
}
|
|
21
|
-
function serializeLibrarySources(sources) {
|
|
22
|
-
return sources.map((source) => source.name ? `${source.name}=${source.root}` : source.root).join(":");
|
|
23
|
-
}
|
|
24
|
-
function flowSourceTier(source, index, total) {
|
|
25
|
-
if (index === total - 1 && source.name === "metamask") return "canonical";
|
|
26
|
-
if (source.name === "personal") return "personal";
|
|
27
|
-
return "team";
|
|
28
|
-
}
|
|
29
|
-
function restoreEnv(key, value) {
|
|
30
|
-
if (value === void 0) delete process.env[key];
|
|
31
|
-
else process.env[key] = value;
|
|
32
|
-
}
|
|
33
|
-
function libraryEntries(argv) {
|
|
34
|
-
const entries = [];
|
|
35
|
-
for (let index = 0; index < argv.length; index += 1) {
|
|
36
|
-
const argument = argv[index];
|
|
37
|
-
if (argument === "--library") {
|
|
38
|
-
const value = argv[index + 1];
|
|
39
|
-
if (value !== void 0) entries.push(value);
|
|
40
|
-
index += 1;
|
|
41
|
-
} else if (argument.startsWith("--library=")) {
|
|
42
|
-
entries.push(argument.slice("--library=".length));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return entries;
|
|
46
|
-
}
|
|
47
|
-
async function handleFlows(argv) {
|
|
48
|
-
const { positional } = parseArgs(argv);
|
|
49
|
-
const subcommand = positional[0];
|
|
50
|
-
if (subcommand === "describe" && !positional[1]) {
|
|
51
|
-
throw usageError("flows describe requires <ref>. Next: mm-harness flows list");
|
|
52
|
-
}
|
|
53
|
-
if (subcommand !== "describe" && positional[1]) {
|
|
54
|
-
throw usageError(`flows ${subcommand ?? "list"} does not accept positional ${positional[1]}.`);
|
|
55
|
-
}
|
|
56
|
-
const configuredLibraries = libraryEntries(argv);
|
|
57
|
-
const sources = await resolveMetaMaskLibrarySources(configuredLibraries);
|
|
58
|
-
if (!sources) {
|
|
59
|
-
throw usageError(
|
|
60
|
-
"flows requires @farmslot/recipe-harness >= 0.3.3 (recipe-library support; flows resolve personal > team > canonical). Next: update the dependency and run yarn install."
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
const forwarded = stripFrontOnlyFlags(argv);
|
|
64
|
-
const jsonMode = forwarded.includes("--json");
|
|
65
|
-
if (!jsonMode) {
|
|
66
|
-
console.error(color("label", "flows resolve by precedence (highest wins; local shadows canonical):"));
|
|
67
|
-
sources.forEach((source, index) => {
|
|
68
|
-
const name = source.name ?? path.basename(source.root);
|
|
69
|
-
console.error(` ${index + 1}. ${color("cmd", name)} ${color("dim", `[${flowSourceTier(source, index, sources.length)}]`)}`);
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
const resolvedSubcommand = subcommand && FLOWS_SUBCOMMANDS.includes(subcommand) ? subcommand : "list";
|
|
73
|
-
const forwardedSubcommandIndex = forwarded.indexOf(resolvedSubcommand);
|
|
74
|
-
const delegatedArgs = forwardedSubcommandIndex === -1 ? forwarded : forwarded.filter((_, index) => index !== forwardedSubcommandIndex);
|
|
75
|
-
const withSubcommand = [resolvedSubcommand, ...delegatedArgs];
|
|
76
|
-
const { runRecipeHarnessCli } = await importRecipeHarnessCli();
|
|
77
|
-
const previousLibraryPath = process.env.RECIPE_LIBRARY_PATH;
|
|
78
|
-
const previousExitCode = process.exitCode;
|
|
79
|
-
process.env.RECIPE_LIBRARY_PATH = serializeLibrarySources(sources);
|
|
80
|
-
process.exitCode = void 0;
|
|
81
|
-
try {
|
|
82
|
-
await runRecipeHarnessCli(["flows", ...withSubcommand], { commandName: "mm-harness" });
|
|
83
|
-
return typeof process.exitCode === "number" ? process.exitCode : EXIT.ok;
|
|
84
|
-
} finally {
|
|
85
|
-
restoreEnv("RECIPE_LIBRARY_PATH", previousLibraryPath);
|
|
86
|
-
process.exitCode = previousExitCode;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
export {
|
|
90
|
-
handleFlows
|
|
91
|
-
};
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"schema_version": 1,
|
|
3
|
-
"kind": "recipe-flow-catalog",
|
|
4
|
-
"owner": "metamask.perps",
|
|
5
|
-
"flows": {
|
|
6
|
-
"perps.clean_market_testnet": {
|
|
7
|
-
"version": 1,
|
|
8
|
-
"description": "Converge Perps to a clean testnet baseline before a proof window: wallet unlocked, requested market selected, no open positions or orders for that market.",
|
|
9
|
-
"paramsSchema": {
|
|
10
|
-
"type": "object",
|
|
11
|
-
"required": ["market"],
|
|
12
|
-
"properties": {
|
|
13
|
-
"market": {
|
|
14
|
-
"type": "string",
|
|
15
|
-
"description": "Market symbol to converge, e.g. BTC."
|
|
16
|
-
},
|
|
17
|
-
"provider": {
|
|
18
|
-
"type": "string",
|
|
19
|
-
"description": "Optional Perps provider, e.g. hyperliquid; omit for the app default."
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
"requiresActions": ["metamask.wallet.ensure_unlocked", "metamask.perps.start_state"],
|
|
24
|
-
"defaultPhase": "start_state",
|
|
25
|
-
"defaultRecord": "trace_only",
|
|
26
|
-
"postcondition": { "path": "$.status", "operator": "eq", "value": "pass" },
|
|
27
|
-
"workflow": {
|
|
28
|
-
"entry": "ensure-wallet",
|
|
29
|
-
"nodes": {
|
|
30
|
-
"ensure-wallet": {
|
|
31
|
-
"action": "metamask.wallet.ensure_unlocked",
|
|
32
|
-
"intent": "Ensure the wallet is unlocked before converging the Perps baseline",
|
|
33
|
-
"next": "start-state"
|
|
34
|
-
},
|
|
35
|
-
"start-state": {
|
|
36
|
-
"action": "metamask.perps.start_state",
|
|
37
|
-
"intent": "Converge Perps to a clean {{params.market}} testnet baseline",
|
|
38
|
-
"profile": "clean_market_testnet",
|
|
39
|
-
"network": "testnet",
|
|
40
|
-
"provider": "{{params.provider}}",
|
|
41
|
-
"market": "{{params.market}}",
|
|
42
|
-
"positions": { "state": "none", "mode": "matching" },
|
|
43
|
-
"orders": { "state": "none", "mode": "matching" },
|
|
44
|
-
"next": "done"
|
|
45
|
-
},
|
|
46
|
-
"done": { "action": "end", "status": "pass" }
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
"examples": [
|
|
50
|
-
{
|
|
51
|
-
"description": "Clean BTC testnet baseline before a visual proof",
|
|
52
|
-
"node": {
|
|
53
|
-
"action": "call",
|
|
54
|
-
"ref": "perps.clean_market_testnet",
|
|
55
|
-
"params": { "market": "BTC" },
|
|
56
|
-
"phase": "start_state",
|
|
57
|
-
"record": "trace_only",
|
|
58
|
-
"intent": "Converge Perps to a clean BTC testnet baseline before proof"
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
]
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|