@deeeed/metamask-harness 0.84.0 → 0.85.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 +34 -0
- package/adapters/extension/console-tail.mjs +11 -7
- package/adapters/extension/ensure-browser.sh +17 -18
- package/adapters/mobile/start-console-forwarder.sh +8 -0
- package/adapters/shared/resolve-slot-ports-core.mjs +48 -6
- package/dist/adapters/extension/actions.js +5 -0
- package/dist/adapters/extension/console-capture.js +18 -0
- package/dist/adapters/extension/fixtures.js +2 -0
- package/dist/adapters/extension/overlay.js +5 -4
- package/dist/adapters/extension/runtime.js +2 -0
- package/dist/adapters/mobile/launch.js +19 -2
- package/dist/adapters/mobile/provision.js +4 -2
- package/dist/adapters/mobile/run.js +2 -1
- package/dist/adapters/mobile/verify.js +15 -7
- package/dist/adapters/web-dapp/actions.js +7 -5
- package/dist/adapters.js +5 -3
- package/dist/command-contract.js +28 -19
- package/dist/commands/check.js +5 -7
- package/dist/commands/debug.js +2 -2
- package/dist/commands/doctor.js +2 -3
- package/dist/commands/domain.js +4 -3
- package/dist/commands/fixtures.js +3 -3
- package/dist/commands/help.js +6 -5
- package/dist/commands/launch/extension.js +9 -7
- package/dist/commands/logs.js +2 -2
- package/dist/commands/prepare.js +4 -4
- package/dist/commands/provision.js +2 -2
- package/dist/commands/review.js +8 -10
- package/dist/commands/runtime-launch.js +2 -0
- package/dist/commands/status.js +4 -2
- package/dist/commands/task-init.js +2 -3
- package/dist/console-classifier.js +3 -2
- package/dist/doctor.js +6 -2
- package/dist/mm-harness-cli.js +19 -6
- package/dist/paths.js +9 -4
- package/dist/recipe-security.js +1 -1
- package/dist/review/knowledge.js +10 -2
- package/dist/runner.js +18 -3
- package/docs/CONTRIBUTING.md +8 -0
- package/docs/RECIPES.md +14 -1
- package/docs/cli-contract.md +7 -6
- package/library/actions/extension/app/assert_no_console_errors.mjs +95 -0
- package/library/actions/extension/platform/cdp.mjs +26 -0
- package/library/actions/mobile/app/assert_no_console_errors.mjs +129 -0
- package/library/actions/shared/console-assert.mjs +174 -0
- package/library/actions/shared/console-collector.mjs +10 -3
- package/library/actions/shared/console-findings.mjs +108 -7
- package/library/actions/web-dapp/app/assert_no_console_errors.mjs +10 -54
- package/library/actions/web-dapp/platform/hud.mjs +2 -9
- package/library/actions/web-dapp/platform/page.mjs +62 -16
- package/library/actions/web-dapp/platform/runtime.mjs +1 -1
- package/library/diagnostics/console-allowlist.json +13 -0
- package/library/manifests/extension.action-manifest.json +36 -0
- package/library/manifests/mobile.action-manifest.json +36 -0
- package/library/manifests/web-dapp.action-manifest.json +1 -1
- package/library/recipes/core/health/check.recipe.json +40 -0
- package/library/recipes/extension/health/check.recipe.json +71 -0
- package/library/recipes/mobile/health/check.recipe.json +71 -0
- package/package.json +9 -9
- package/site/assets/help-recipes.json +2 -1
|
@@ -1237,6 +1237,42 @@
|
|
|
1237
1237
|
},
|
|
1238
1238
|
"execution_capabilities": []
|
|
1239
1239
|
},
|
|
1240
|
+
"metamask.app.assert_no_console_errors": {
|
|
1241
|
+
"description": "Fail when MetaMask (service worker or UI pages) logged an error or uncaught exception that no console allowlist (the bundled library's, then each recipe library's diagnostics/console-allowlist.json) marks as known noise, judging the events since the launch began, by their own timestamps. Reads extension-console.log from the offset mm-harness launch records when it starts, and leaves out records the collector stamps with an event time before the launch (a replaced collector's replay of a browser the launch kept); with no recorded launch it fails unless since is start-of-log. The same classification feeds run diagnostics. Fails as unavailable unless this runtime's console collector runs on the run's CDP port and a control line logged in MetaMask's service worker or page reaches extension-console.log. Allowlist entries are exact signatures (schemaVersion 3).",
|
|
1242
|
+
"execution_capabilities": ["host-read-export"],
|
|
1243
|
+
"schema": {
|
|
1244
|
+
"type": "object",
|
|
1245
|
+
"properties": {
|
|
1246
|
+
"levels": {
|
|
1247
|
+
"type": "array",
|
|
1248
|
+
"items": { "type": "string", "enum": ["error", "exception", "warning"] },
|
|
1249
|
+
"description": "Default [\"error\",\"exception\"]."
|
|
1250
|
+
},
|
|
1251
|
+
"since": {
|
|
1252
|
+
"type": "string",
|
|
1253
|
+
"enum": ["launch", "start-of-log"],
|
|
1254
|
+
"default": "launch"
|
|
1255
|
+
},
|
|
1256
|
+
"allowlist_root": {
|
|
1257
|
+
"type": "string",
|
|
1258
|
+
"description": "An extra directory holding diagnostics/console-allowlist.json."
|
|
1259
|
+
},
|
|
1260
|
+
"timeout_ms": {
|
|
1261
|
+
"type": "number",
|
|
1262
|
+
"minimum": 1,
|
|
1263
|
+
"description": "Maximum time in milliseconds to wait for the capture control line (default 8000)."
|
|
1264
|
+
}
|
|
1265
|
+
},
|
|
1266
|
+
"additionalProperties": false
|
|
1267
|
+
},
|
|
1268
|
+
"examples": [
|
|
1269
|
+
{
|
|
1270
|
+
"action": "metamask.app.assert_no_console_errors",
|
|
1271
|
+
"intent": "Prove MetaMask logged no unexpected error since launch",
|
|
1272
|
+
"next": "done"
|
|
1273
|
+
}
|
|
1274
|
+
]
|
|
1275
|
+
},
|
|
1240
1276
|
"app.network_assert": {
|
|
1241
1277
|
"description": "Assert a previously indexed app.network_capture summary without hiding its diagnostics on failure.",
|
|
1242
1278
|
"examples": [
|
|
@@ -1260,6 +1260,42 @@
|
|
|
1260
1260
|
},
|
|
1261
1261
|
"execution_capabilities": []
|
|
1262
1262
|
},
|
|
1263
|
+
"metamask.app.assert_no_console_errors": {
|
|
1264
|
+
"description": "Fail when the app logged an error or uncaught exception that no console allowlist (the bundled library's, then each recipe library's diagnostics/console-allowlist.json) marks as known noise, judging the events since the launch began, by their own timestamps. Reads app-console.log from the adapter-rn console forwarder, which stamps each line with the event's own time: mm-harness launch records when it starts, and lines a reused app runtime replays from before then are left out; with no recorded launch it fails unless since is start-of-log. Only the device the bridge selects for the run (the one the control line comes back from) is judged; when that line names no device, every device is, reported as devices: \"all\". The same classification feeds run diagnostics. Fails as unavailable unless this checkout's forwarder is running and a control line logged inside the app through the debug bridge reaches app-console.log; the opaque release runtime has no bridge and always fails as unavailable. Allowlist entries are exact signatures (schemaVersion 3).",
|
|
1265
|
+
"execution_capabilities": ["host-read-export"],
|
|
1266
|
+
"schema": {
|
|
1267
|
+
"type": "object",
|
|
1268
|
+
"properties": {
|
|
1269
|
+
"levels": {
|
|
1270
|
+
"type": "array",
|
|
1271
|
+
"items": { "type": "string", "enum": ["error", "exception", "warning"] },
|
|
1272
|
+
"description": "Default [\"error\",\"exception\"]."
|
|
1273
|
+
},
|
|
1274
|
+
"since": {
|
|
1275
|
+
"type": "string",
|
|
1276
|
+
"enum": ["launch", "start-of-log"],
|
|
1277
|
+
"default": "launch"
|
|
1278
|
+
},
|
|
1279
|
+
"allowlist_root": {
|
|
1280
|
+
"type": "string",
|
|
1281
|
+
"description": "An extra directory holding diagnostics/console-allowlist.json."
|
|
1282
|
+
},
|
|
1283
|
+
"timeout_ms": {
|
|
1284
|
+
"type": "number",
|
|
1285
|
+
"minimum": 1,
|
|
1286
|
+
"description": "Maximum time in milliseconds to wait for the capture control line (default 8000)."
|
|
1287
|
+
}
|
|
1288
|
+
},
|
|
1289
|
+
"additionalProperties": false
|
|
1290
|
+
},
|
|
1291
|
+
"examples": [
|
|
1292
|
+
{
|
|
1293
|
+
"action": "metamask.app.assert_no_console_errors",
|
|
1294
|
+
"intent": "Prove the app logged no unexpected error since launch",
|
|
1295
|
+
"next": "done"
|
|
1296
|
+
}
|
|
1297
|
+
]
|
|
1298
|
+
},
|
|
1263
1299
|
"app.network_assert": {
|
|
1264
1300
|
"description": "Assert a previously indexed app.network_capture summary without hiding its diagnostics on failure.",
|
|
1265
1301
|
"examples": [
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"app.hud": {
|
|
20
|
-
"description": "Display recipe progress in an overlay on the app tab: recipe, step N/M, the current node intent and the last pass/fail.
|
|
20
|
+
"description": "Display recipe progress in an overlay on the app tab: recipe, step N/M, the current node intent and the last pass/fail. Drawn on a MetaMask wallet page only for the length of a surface=wallet ui.screenshot; ignored by clicks and page text; kept in every ui.screenshot. Drawn in a headless or headful browser unless --hud hide, which also clears the HUD an earlier run left.",
|
|
21
21
|
"examples": [
|
|
22
22
|
{
|
|
23
23
|
"action": "app.hud",
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
|
|
3
|
+
"title": "MetaMask Core health check",
|
|
4
|
+
"description": "Read-only check to run before ticket work: the headless Perps controller imports and answers one bounded HyperLiquid testnet account read. A failed precondition stops at the node named after its error; that node's intent gives the recovery. Places no orders.",
|
|
5
|
+
"paramsSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"timeout_ms": { "type": "integer", "minimum": 1000, "default": 60000 }
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"workflow": {
|
|
13
|
+
"entry": "status",
|
|
14
|
+
"nodes": {
|
|
15
|
+
"status": {
|
|
16
|
+
"action": "app.status",
|
|
17
|
+
"next": "CONTROLLER_UNAVAILABLE",
|
|
18
|
+
"intent": "Record the resolved Core checkout"
|
|
19
|
+
},
|
|
20
|
+
"CONTROLLER_UNAVAILABLE": {
|
|
21
|
+
"action": "metamask.perps.read_account",
|
|
22
|
+
"network": "testnet",
|
|
23
|
+
"timeout_ms": "{{params.timeout_ms}}",
|
|
24
|
+
"next": "ACCOUNT_READ_FAILED",
|
|
25
|
+
"intent": "CONTROLLER_UNAVAILABLE unless the Perps controller imports and reads the testnet account in time. Recovery: mm-harness doctor --fix"
|
|
26
|
+
},
|
|
27
|
+
"ACCOUNT_READ_FAILED": {
|
|
28
|
+
"action": "assert_output",
|
|
29
|
+
"source": "CONTROLLER_UNAVAILABLE",
|
|
30
|
+
"assert": { "path": "$.accountState.totalBalance", "operator": "matches", "value": "^-?[0-9]+(\\.[0-9]+)?$" },
|
|
31
|
+
"next": "done",
|
|
32
|
+
"intent": "ACCOUNT_READ_FAILED unless the read returned a numeric balance; the controller reports an unreachable venue as a placeholder. Recovery: check network access to HyperLiquid testnet, then rerun"
|
|
33
|
+
},
|
|
34
|
+
"done": {
|
|
35
|
+
"action": "end",
|
|
36
|
+
"status": "pass"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
|
|
3
|
+
"title": "MetaMask Extension health check",
|
|
4
|
+
"description": "Read-only check to run before ticket work: the extension answers over CDP, onboarding is done, and the wallet is unlocked on a selected account at wallet home. A failed precondition stops at the node named after its error; that node's intent gives the recovery. Changes no app state.",
|
|
5
|
+
"paramsSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"capture_path": { "type": "string", "default": "screenshots/health-check.png" }
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"workflow": {
|
|
13
|
+
"entry": "APP_NOT_RUNNING",
|
|
14
|
+
"nodes": {
|
|
15
|
+
"APP_NOT_RUNNING": {
|
|
16
|
+
"action": "cdp.target",
|
|
17
|
+
"require_reachable": true,
|
|
18
|
+
"next": "state",
|
|
19
|
+
"intent": "APP_NOT_RUNNING unless the extension answers over CDP. Recovery: mm-harness launch --verify"
|
|
20
|
+
},
|
|
21
|
+
"state": {
|
|
22
|
+
"action": "metamask.wallet.read_state",
|
|
23
|
+
"next": "ONBOARDING",
|
|
24
|
+
"intent": "Read the selected account, lock state and page without changing them"
|
|
25
|
+
},
|
|
26
|
+
"ONBOARDING": {
|
|
27
|
+
"action": "assert_output",
|
|
28
|
+
"source": "state",
|
|
29
|
+
"assert": { "path": "$.state.completedOnboarding", "operator": "eq", "value": true },
|
|
30
|
+
"next": "WALLET_LOCKED",
|
|
31
|
+
"intent": "ONBOARDING if onboarding is not complete. Recovery: mm-harness run wallet.import"
|
|
32
|
+
},
|
|
33
|
+
"WALLET_LOCKED": {
|
|
34
|
+
"action": "assert_output",
|
|
35
|
+
"source": "state",
|
|
36
|
+
"assert": { "path": "$.state.passwordInput", "operator": "falsy" },
|
|
37
|
+
"next": "NO_SELECTED_ACCOUNT",
|
|
38
|
+
"intent": "WALLET_LOCKED if the unlock page is showing. Recovery: mm-harness run wallet.smoke"
|
|
39
|
+
},
|
|
40
|
+
"NO_SELECTED_ACCOUNT": {
|
|
41
|
+
"action": "assert_output",
|
|
42
|
+
"source": "state",
|
|
43
|
+
"assert": { "path": "$.state.selectedAccount.address", "operator": "not_null" },
|
|
44
|
+
"next": "NOT_ON_HOME",
|
|
45
|
+
"intent": "NO_SELECTED_ACCOUNT if the wallet reports no selected account. Recovery: mm-harness run wallet.import"
|
|
46
|
+
},
|
|
47
|
+
"NOT_ON_HOME": {
|
|
48
|
+
"action": "assert_output",
|
|
49
|
+
"source": "state",
|
|
50
|
+
"assert": { "path": "$.state.href", "operator": "matches", "value": "/(home|sidepanel)\\.html#/?$" },
|
|
51
|
+
"next": "CONSOLE_ERRORS",
|
|
52
|
+
"intent": "NOT_ON_HOME unless wallet home is showing. Recovery: a ui.navigate node with page home, then rerun"
|
|
53
|
+
},
|
|
54
|
+
"CONSOLE_ERRORS": {
|
|
55
|
+
"action": "metamask.app.assert_no_console_errors",
|
|
56
|
+
"next": "screenshot",
|
|
57
|
+
"intent": "CONSOLE_ERRORS if the app logged an error outside the console allowlist since launch. Recovery: fix the error, or allowlist known noise with a reason in a library's diagnostics/console-allowlist.json"
|
|
58
|
+
},
|
|
59
|
+
"screenshot": {
|
|
60
|
+
"action": "ui.screenshot",
|
|
61
|
+
"path": "{{params.capture_path}}",
|
|
62
|
+
"next": "done",
|
|
63
|
+
"intent": "Record the ready wallet home as evidence"
|
|
64
|
+
},
|
|
65
|
+
"done": {
|
|
66
|
+
"action": "end",
|
|
67
|
+
"status": "pass"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://farmslot.io/schemas/recipe-v1.schema.json",
|
|
3
|
+
"title": "MetaMask Mobile health check",
|
|
4
|
+
"description": "Read-only check to run before ticket work: the app answers, onboarding is done, and the wallet is unlocked on a selected account at wallet home. A failed precondition stops at the node named after its error; that node's intent gives the recovery. Changes no app state.",
|
|
5
|
+
"paramsSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"capture_path": { "type": "string", "default": "screenshots/health-check.png" }
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"workflow": {
|
|
13
|
+
"entry": "APP_NOT_RUNNING",
|
|
14
|
+
"nodes": {
|
|
15
|
+
"APP_NOT_RUNNING": {
|
|
16
|
+
"action": "cdp.target",
|
|
17
|
+
"require_reachable": true,
|
|
18
|
+
"next": "state",
|
|
19
|
+
"intent": "APP_NOT_RUNNING unless the app's debug bridge answers. Recovery: mm-harness launch ios|android --verify"
|
|
20
|
+
},
|
|
21
|
+
"state": {
|
|
22
|
+
"action": "metamask.wallet.read_state",
|
|
23
|
+
"next": "ONBOARDING",
|
|
24
|
+
"intent": "Read the selected account and route without changing them"
|
|
25
|
+
},
|
|
26
|
+
"ONBOARDING": {
|
|
27
|
+
"action": "assert_output",
|
|
28
|
+
"source": "state",
|
|
29
|
+
"assert": { "path": "$.route.name", "operator": "matches", "value": "^(?!Onboarding|OptinMetrics)" },
|
|
30
|
+
"next": "WALLET_LOCKED",
|
|
31
|
+
"intent": "ONBOARDING if the app is still in onboarding. Recovery: mm-harness run wallet.import"
|
|
32
|
+
},
|
|
33
|
+
"WALLET_LOCKED": {
|
|
34
|
+
"action": "assert_output",
|
|
35
|
+
"source": "state",
|
|
36
|
+
"assert": { "path": "$.route.name", "operator": "ne", "value": "Login" },
|
|
37
|
+
"next": "NO_SELECTED_ACCOUNT",
|
|
38
|
+
"intent": "WALLET_LOCKED if the unlock screen is showing. Recovery: mm-harness run wallet.smoke"
|
|
39
|
+
},
|
|
40
|
+
"NO_SELECTED_ACCOUNT": {
|
|
41
|
+
"action": "assert_output",
|
|
42
|
+
"source": "state",
|
|
43
|
+
"assert": { "path": "$.account.address", "operator": "not_null" },
|
|
44
|
+
"next": "NOT_ON_HOME",
|
|
45
|
+
"intent": "NO_SELECTED_ACCOUNT if the wallet reports no selected account. Recovery: mm-harness run wallet.import"
|
|
46
|
+
},
|
|
47
|
+
"NOT_ON_HOME": {
|
|
48
|
+
"action": "assert_output",
|
|
49
|
+
"source": "state",
|
|
50
|
+
"assert": { "path": "$.route.name", "operator": "eq", "value": "WalletView" },
|
|
51
|
+
"next": "CONSOLE_ERRORS",
|
|
52
|
+
"intent": "NOT_ON_HOME unless wallet home is showing. Recovery: a ui.navigate node with page home, then rerun"
|
|
53
|
+
},
|
|
54
|
+
"CONSOLE_ERRORS": {
|
|
55
|
+
"action": "metamask.app.assert_no_console_errors",
|
|
56
|
+
"next": "screenshot",
|
|
57
|
+
"intent": "CONSOLE_ERRORS if the app logged an error outside the console allowlist since launch. Recovery: fix the error, or allowlist known noise with a reason in a library's diagnostics/console-allowlist.json"
|
|
58
|
+
},
|
|
59
|
+
"screenshot": {
|
|
60
|
+
"action": "ui.screenshot",
|
|
61
|
+
"path": "{{params.capture_path}}",
|
|
62
|
+
"next": "done",
|
|
63
|
+
"intent": "Record the ready wallet home as evidence"
|
|
64
|
+
},
|
|
65
|
+
"done": {
|
|
66
|
+
"action": "end",
|
|
67
|
+
"status": "pass"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeeed/metamask-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.85.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mm-harness": "bin/mm-harness"
|
|
@@ -21,15 +21,15 @@
|
|
|
21
21
|
"check:syntax": "find . -name '*.mjs' -print0 | xargs -0 -n1 node --check"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@farmslot/adapter-node": "0.1.
|
|
25
|
-
"@farmslot/adapter-rn": "0.19.
|
|
26
|
-
"@farmslot/adapter-sdk": "0.
|
|
27
|
-
"@farmslot/adapter-web": "0.6.
|
|
28
|
-
"@farmslot/agent-runtime": "0.17.
|
|
24
|
+
"@farmslot/adapter-node": "0.1.6",
|
|
25
|
+
"@farmslot/adapter-rn": "0.19.3",
|
|
26
|
+
"@farmslot/adapter-sdk": "0.8.0",
|
|
27
|
+
"@farmslot/adapter-web": "0.6.4",
|
|
28
|
+
"@farmslot/agent-runtime": "0.17.1",
|
|
29
29
|
"@farmslot/handoff": "^0.3.1",
|
|
30
|
-
"@farmslot/protocol": "0.
|
|
31
|
-
"@farmslot/recipe-cli": "0.
|
|
32
|
-
"@farmslot/recipe-runner": "0.
|
|
30
|
+
"@farmslot/protocol": "0.35.0",
|
|
31
|
+
"@farmslot/recipe-cli": "0.11.0",
|
|
32
|
+
"@farmslot/recipe-runner": "0.28.0",
|
|
33
33
|
"agent-device": "0.19.3",
|
|
34
34
|
"commander": "^12.0.0",
|
|
35
35
|
"esbuild": "0.28.1",
|