@deeeed/metamask-harness 0.31.0 → 0.33.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 +16 -0
- package/adapters/extension/verify.sh +16 -4
- package/dist/adapters.js +73 -1
- package/dist/commands/self-test.js +1 -1
- package/dist/paths.js +7 -0
- package/dist/runner.js +13 -2
- package/docs/RECIPES.md +5 -2
- package/library/manifests/extension.action-manifest.json +210 -2
- package/library/manifests/mobile.action-manifest.json +214 -0
- package/package.json +6 -4
- /package/library/recipes/{perps/clean-market-testnet.core.recipe.json → core/perps/clean-market-testnet.recipe.json} +0 -0
- /package/library/recipes/{perps/order-lifecycle.core.recipe.json → core/perps/order-lifecycle.recipe.json} +0 -0
- /package/library/recipes/{perps/read-markets.core.recipe.json → core/perps/read-markets.recipe.json} +0 -0
- /package/library/recipes/{perps/smoke.core.recipe.json → core/perps/smoke.recipe.json} +0 -0
- /package/library/recipes/{perps/trading-lifecycle.core.recipe.json → core/perps/trading-lifecycle.recipe.json} +0 -0
- /package/library/recipes/{runner/smoke.core.recipe.json → core/runner/smoke.recipe.json} +0 -0
- /package/library/recipes/{perps/smoke.extension.recipe.json → extension/perps/smoke.recipe.json} +0 -0
- /package/library/recipes/{runner/action-validation.extension.recipe.json → extension/runner/action-validation.recipe.json} +0 -0
- /package/library/recipes/{runner/smoke.extension.recipe.json → extension/runner/smoke.recipe.json} +0 -0
- /package/library/recipes/{wallet/smoke.extension.recipe.json → extension/wallet/smoke.recipe.json} +0 -0
- /package/library/recipes/{app/lifecycle.android-smoke.mobile.recipe.json → mobile/app/lifecycle.android-smoke.recipe.json} +0 -0
- /package/library/recipes/{perps/performance.background-resume.mobile.recipe.json → mobile/perps/performance.background-resume.recipe.json} +0 -0
- /package/library/recipes/{perps/performance.cold-start.mobile.recipe.json → mobile/perps/performance.cold-start.recipe.json} +0 -0
- /package/library/recipes/{perps/performance.mobile.recipe.json → mobile/perps/performance.recipe.json} +0 -0
- /package/library/recipes/{perps/performance.warm-start.mobile.recipe.json → mobile/perps/performance.warm-start.recipe.json} +0 -0
- /package/library/recipes/{perps/smoke.mobile.recipe.json → mobile/perps/smoke.recipe.json} +0 -0
- /package/library/recipes/{runner/action-validation.mobile.recipe.json → mobile/runner/action-validation.recipe.json} +0 -0
- /package/library/recipes/{runner/smoke.mobile.recipe.json → mobile/runner/smoke.recipe.json} +0 -0
- /package/library/recipes/{wallet/smoke.mobile.recipe.json → mobile/wallet/smoke.recipe.json} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.33.0 - 2026-08-03
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Expose standard full-surface capture and continuous UI gestures for Mobile and Extension by delegating to the shared native and browser transports.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Upgrade `@farmslot/agent-runtime` to 0.7.0, `@farmslot/protocol` to 0.18.0, and `@farmslot/recipe-harness` to 0.14.0, and add `@farmslot/expo-recipe` 0.7.1 with `agent-device` 0.19.3 for the native UI provider.
|
|
14
|
+
|
|
15
|
+
## 0.32.0 - 2026-08-02
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- Organize bundled platform recipe variants under `library/recipes/<adapter>/` while retaining temporary compatibility with legacy filename suffixes.
|
|
20
|
+
|
|
5
21
|
## 0.31.0 - 2026-08-02
|
|
6
22
|
|
|
7
23
|
### Added
|
|
@@ -88,7 +88,7 @@ RUNNER_BIN="$HARNESS_DIR/runner/bin/mm-harness"
|
|
|
88
88
|
# --out (optional): a task-local recipes dir. Resolve it safely within the target
|
|
89
89
|
# (resolve_harness_out rejects absolute/.. escapes) and prefer its smoke recipe so
|
|
90
90
|
# `live --out <dir>` does not silently fall back to the installed default.
|
|
91
|
-
SMOKE_RECIPE="$HARNESS_DIR/runner/recipes/runner/smoke.
|
|
91
|
+
SMOKE_RECIPE="$HARNESS_DIR/runner/recipes/extension/runner/smoke.recipe.json"
|
|
92
92
|
if [ -n "$OUT" ]; then
|
|
93
93
|
# Fail fast on a task-local --out that does not contain the requested recipe.
|
|
94
94
|
# Silently falling back to the installed default would validate a different
|
|
@@ -98,11 +98,23 @@ if [ -n "$OUT" ]; then
|
|
|
98
98
|
echo "extension verify: --out '$OUT' did not resolve to a safe path under the target." >&2
|
|
99
99
|
exit 2
|
|
100
100
|
fi
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
CANONICAL_SMOKE_RECIPE="$OUT_ABS/extension/runner/smoke.recipe.json"
|
|
102
|
+
LEGACY_SMOKE_RECIPE="$OUT_ABS/runner/smoke.extension.recipe.json"
|
|
103
|
+
if [ -f "$CANONICAL_SMOKE_RECIPE" ] && [ -f "$LEGACY_SMOKE_RECIPE" ]; then
|
|
104
|
+
echo "extension verify: --out '$OUT' declares runner.smoke for extension in both canonical and legacy paths." >&2
|
|
105
|
+
echo "Next: Remove $LEGACY_SMOKE_RECIPE and rerun verification." >&2
|
|
103
106
|
exit 2
|
|
104
107
|
fi
|
|
105
|
-
|
|
108
|
+
if [ -f "$CANONICAL_SMOKE_RECIPE" ]; then
|
|
109
|
+
SMOKE_RECIPE="$CANONICAL_SMOKE_RECIPE"
|
|
110
|
+
elif [ -f "$LEGACY_SMOKE_RECIPE" ]; then
|
|
111
|
+
SMOKE_RECIPE="$LEGACY_SMOKE_RECIPE"
|
|
112
|
+
else
|
|
113
|
+
echo "extension verify: --out '$OUT' has no extension runner.smoke recipe." >&2
|
|
114
|
+
echo "Next: Add extension/runner/smoke.recipe.json under $OUT_ABS or omit --out." >&2
|
|
115
|
+
exit 2
|
|
116
|
+
fi
|
|
117
|
+
unset CANONICAL_SMOKE_RECIPE LEGACY_SMOKE_RECIPE
|
|
106
118
|
fi
|
|
107
119
|
ARTIFACTS="${ARTIFACTS:-$HARNESS_DIR/verify/$(date -u +%Y%m%dT%H%M%SZ)}"
|
|
108
120
|
mkdir -p "$ARTIFACTS/logs"
|
package/dist/adapters.js
CHANGED
|
@@ -6,6 +6,13 @@ import {
|
|
|
6
6
|
import { withExtensionPage } from "../library/actions/extension/platform/cdp.mjs";
|
|
7
7
|
import { bridgeCommand, evalSync, MOBILE_BRIDGE_ERROR_CODES, selectBridgeStatusEntry, simulatorScreenshot } from "../library/actions/mobile/platform/bridge.mjs";
|
|
8
8
|
import { observeNativeUi } from "../library/actions/mobile/platform/observe-ui.mjs";
|
|
9
|
+
const NATIVE_PROVIDER_UI_ACTIONS = /* @__PURE__ */ new Set([
|
|
10
|
+
"ui.swipe",
|
|
11
|
+
"ui.pan",
|
|
12
|
+
"ui.drag",
|
|
13
|
+
"ui.long_press",
|
|
14
|
+
"ui.capture_surface"
|
|
15
|
+
]);
|
|
9
16
|
function sleep(ms) {
|
|
10
17
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
18
|
}
|
|
@@ -480,7 +487,7 @@ function createMetaMaskUiTransport(platform, harness, preparedLiveAdapters) {
|
|
|
480
487
|
return {
|
|
481
488
|
async execute(action) {
|
|
482
489
|
throw new Error(
|
|
483
|
-
`core adapter is headless and cannot execute UI action ${action}.
|
|
490
|
+
`core adapter is headless and cannot execute UI action ${action}. Next: mm-harness actions --matrix`
|
|
484
491
|
);
|
|
485
492
|
}
|
|
486
493
|
};
|
|
@@ -516,10 +523,75 @@ function createMetaMaskUiTransport(platform, harness, preparedLiveAdapters) {
|
|
|
516
523
|
if (live) return live.output;
|
|
517
524
|
throw new Error(`ui.navigate requires library/actions/${platform}/ui/navigate.mjs.`);
|
|
518
525
|
}
|
|
526
|
+
if (platform === "mobile" && NATIVE_PROVIDER_UI_ACTIONS.has(action)) {
|
|
527
|
+
return executeNativeProviderAction(action, node, context, harness.createNativeUiTransport);
|
|
528
|
+
}
|
|
519
529
|
return base.execute(action, action === "ui.wait_for" ? normalizeUiWaitNode(node) : node, context);
|
|
520
530
|
}
|
|
521
531
|
};
|
|
522
532
|
}
|
|
533
|
+
async function executeNativeProviderAction(action, node, context, createTransport) {
|
|
534
|
+
if (!createTransport) {
|
|
535
|
+
throw new Error(
|
|
536
|
+
`${action} requires the MetaMask native UI provider. Next: npm install -g @deeeed/metamask-harness@latest`
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
const platform = mobileNativePlatform(context.env);
|
|
540
|
+
const device = platform === "android" ? context.env.ADB_SERIAL ?? context.env.ANDROID_SERIAL ?? process.env.ADB_SERIAL ?? process.env.ANDROID_SERIAL : context.env.SIM_UDID ?? context.env.IOS_SIMULATOR ?? process.env.SIM_UDID ?? process.env.IOS_SIMULATOR;
|
|
541
|
+
if (!device) {
|
|
542
|
+
throw new Error(
|
|
543
|
+
`${action} requires one selected ${platform} device. Next: mm-harness status --adapter mobile --all-devices --json`
|
|
544
|
+
);
|
|
545
|
+
}
|
|
546
|
+
const app = platform === "android" ? context.env.ANDROID_PACKAGE_ID ?? process.env.ANDROID_PACKAGE_ID : context.env.IOS_BUNDLE_ID ?? process.env.IOS_BUNDLE_ID;
|
|
547
|
+
if (!app) {
|
|
548
|
+
const variable = platform === "android" ? "ANDROID_PACKAGE_ID" : "IOS_BUNDLE_ID";
|
|
549
|
+
throw new Error(
|
|
550
|
+
`${action} requires the selected MetaMask app id. Next: export ${variable}=<installed-app-id>`
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
const session = `mm-harness-${process.pid}-${context.nodeId}`.replace(/[^a-zA-Z0-9._-]/gu, "-");
|
|
554
|
+
let transport;
|
|
555
|
+
try {
|
|
556
|
+
transport = await createTransport({ platform, device, app, session });
|
|
557
|
+
} catch (error) {
|
|
558
|
+
throw new Error(
|
|
559
|
+
`${action} could not start the MetaMask native UI provider. Next: npm install -g @deeeed/metamask-harness@latest`,
|
|
560
|
+
{ cause: error }
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
let executionError;
|
|
564
|
+
let output;
|
|
565
|
+
try {
|
|
566
|
+
output = await transport.execute(action, node, context);
|
|
567
|
+
} catch (error) {
|
|
568
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
569
|
+
executionError = /^Native recipe actions require the optional agent-device provider:/u.test(message) ? new Error(
|
|
570
|
+
`${action} could not start the MetaMask native UI provider. Next: npm install -g @deeeed/metamask-harness@latest`,
|
|
571
|
+
{ cause: error }
|
|
572
|
+
) : error;
|
|
573
|
+
}
|
|
574
|
+
let closeError;
|
|
575
|
+
try {
|
|
576
|
+
await transport.close?.();
|
|
577
|
+
} catch (error) {
|
|
578
|
+
closeError = error;
|
|
579
|
+
}
|
|
580
|
+
if (executionError && closeError) {
|
|
581
|
+
const message = executionError instanceof Error ? executionError.message : String(executionError);
|
|
582
|
+
throw new AggregateError([executionError, closeError], message);
|
|
583
|
+
}
|
|
584
|
+
if (executionError) throw executionError;
|
|
585
|
+
if (closeError) throw closeError;
|
|
586
|
+
return output;
|
|
587
|
+
}
|
|
588
|
+
function mobileNativePlatform(env) {
|
|
589
|
+
if (env.PLATFORM === "android" || env.PLATFORM === "ios") return env.PLATFORM;
|
|
590
|
+
if (env.ADB_SERIAL || env.ANDROID_SERIAL) return "android";
|
|
591
|
+
if (env.SIM_UDID || env.IOS_SIMULATOR) return "ios";
|
|
592
|
+
if (process.env.PLATFORM === "android" || process.env.PLATFORM === "ios") return process.env.PLATFORM;
|
|
593
|
+
return process.env.ADB_SERIAL || process.env.ANDROID_SERIAL ? "android" : "ios";
|
|
594
|
+
}
|
|
523
595
|
function normalizeUiWaitNode(node) {
|
|
524
596
|
if (node.expected !== void 0 || typeof node.visible !== "boolean") return node;
|
|
525
597
|
return { ...node, expected: node.visible ? "visible" : "absent" };
|
|
@@ -26,7 +26,7 @@ async function runSelfTest(options) {
|
|
|
26
26
|
const manifest = loadActionManifest(adapter);
|
|
27
27
|
const manifestValidation = await validateManifest(manifest);
|
|
28
28
|
const smokeRecipe = recipePath(
|
|
29
|
-
adapter === "mobile" ? "runner/smoke.
|
|
29
|
+
adapter === "mobile" ? "mobile/runner/smoke.recipe.json" : "extension/runner/smoke.recipe.json"
|
|
30
30
|
);
|
|
31
31
|
const artifactsDir = path.join(root, adapter);
|
|
32
32
|
const result = await runRecipe(adapter, smokeRecipe, artifactsDir, runnerDir, void 0, {
|
package/dist/paths.js
CHANGED
|
@@ -128,6 +128,12 @@ async function importRecipeHarnessRuntimeReactNativeBridge() {
|
|
|
128
128
|
"packages/recipe-harness/src/runtime/react-native-bridge.ts"
|
|
129
129
|
);
|
|
130
130
|
}
|
|
131
|
+
async function importMetaMaskNativeUiProvider() {
|
|
132
|
+
return importProtocolPackage(
|
|
133
|
+
"@farmslot/expo-recipe",
|
|
134
|
+
"packages/expo-recipe/src/index.ts"
|
|
135
|
+
);
|
|
136
|
+
}
|
|
131
137
|
async function importRecipeHarnessCli() {
|
|
132
138
|
return importProtocolPackage(
|
|
133
139
|
"@farmslot/recipe-harness/cli",
|
|
@@ -164,6 +170,7 @@ export {
|
|
|
164
170
|
DEFAULT_RECIPE_RUNTIME_DIR,
|
|
165
171
|
assertAdapter,
|
|
166
172
|
extensionIdPath,
|
|
173
|
+
importMetaMaskNativeUiProvider,
|
|
167
174
|
importRecipeHarness,
|
|
168
175
|
importRecipeHarnessAppLifecycle,
|
|
169
176
|
importRecipeHarnessCli,
|
package/dist/runner.js
CHANGED
|
@@ -12,7 +12,14 @@ import {
|
|
|
12
12
|
prepareLiveAdapterScript
|
|
13
13
|
} from "./live-adapter-contract.js";
|
|
14
14
|
import { createMetaMaskRecordingTargetProvider } from "./recording-target.js";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
importMetaMaskNativeUiProvider,
|
|
17
|
+
importRecipeHarness,
|
|
18
|
+
importRecipeHarnessAppLifecycle,
|
|
19
|
+
importRecipeHarnessRuntimeCdp,
|
|
20
|
+
importRecipeHarnessRuntimeReactNativeBridge,
|
|
21
|
+
runnerDir
|
|
22
|
+
} from "./paths.js";
|
|
16
23
|
const OFFICIAL_ACTIONS = new Set(OFFICIAL_RECIPE_ACTIONS);
|
|
17
24
|
async function createMetaMaskMobileRunner(options = {}) {
|
|
18
25
|
return createMetaMaskRunner(
|
|
@@ -51,7 +58,11 @@ async function createMetaMaskRunner(adapter, actionManifest, options = {}) {
|
|
|
51
58
|
actions: actions.filter((action) => !projectOwnedOfficialActions.has(action)),
|
|
52
59
|
transport: createMetaMaskUiTransport(adapter, {
|
|
53
60
|
createCdpWebUiTransport,
|
|
54
|
-
createReactNativeBridgeUiTransport
|
|
61
|
+
createReactNativeBridgeUiTransport,
|
|
62
|
+
async createNativeUiTransport(options2) {
|
|
63
|
+
const { createAgentDeviceUiTransport } = await importMetaMaskNativeUiProvider();
|
|
64
|
+
return createAgentDeviceUiTransport(options2);
|
|
65
|
+
}
|
|
55
66
|
}, preparedLiveAdapters)
|
|
56
67
|
});
|
|
57
68
|
const existing = new Set([...core, ...ui].map((entry) => entry.action));
|
package/docs/RECIPES.md
CHANGED
|
@@ -116,7 +116,7 @@ The protocol is authoritative:
|
|
|
116
116
|
team-recipes/
|
|
117
117
|
manifests/extension.action-manifest.json
|
|
118
118
|
actions/extension/wallet/ensure_ready.mjs
|
|
119
|
-
recipes/onboarding/smoke.
|
|
119
|
+
recipes/extension/onboarding/smoke.recipe.json
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
```bash
|
|
@@ -129,7 +129,10 @@ mm-harness run onboarding.smoke --plan
|
|
|
129
129
|
Use `--library wallet=/path/to/library` for one command. The alias is the
|
|
130
130
|
source name; without one, the directory name is used. Resolution follows the
|
|
131
131
|
explicit library order, then bundled MetaMask. Adapter-specific variants are
|
|
132
|
-
selected deterministically
|
|
132
|
+
selected deterministically from `recipes/<adapter>/<domain>/`. Legacy
|
|
133
|
+
`*.<adapter>.recipe.json` paths remain readable during migration, but new and
|
|
134
|
+
migrated libraries use the adapter-first layout. A file cannot declare its
|
|
135
|
+
adapter through both forms. Every run records the root recipe, exact resolved
|
|
133
136
|
dependency documents, their digests, call edges, selected sources, and shadows.
|
|
134
137
|
|
|
135
138
|
## Direct product access
|
|
@@ -664,6 +664,183 @@
|
|
|
664
664
|
"additionalProperties": false
|
|
665
665
|
}
|
|
666
666
|
},
|
|
667
|
+
"ui.swipe": {
|
|
668
|
+
"description": "Swipe from a test-id target or screen coordinates in one cardinal direction through the shared browser UI transport.",
|
|
669
|
+
"schema": {
|
|
670
|
+
"type": "object",
|
|
671
|
+
"properties": {
|
|
672
|
+
"target": {
|
|
673
|
+
"type": ["string", "object"],
|
|
674
|
+
"properties": {
|
|
675
|
+
"x": { "type": "number" },
|
|
676
|
+
"y": { "type": "number" }
|
|
677
|
+
},
|
|
678
|
+
"required": ["x", "y"],
|
|
679
|
+
"additionalProperties": false
|
|
680
|
+
},
|
|
681
|
+
"direction": {
|
|
682
|
+
"type": "string",
|
|
683
|
+
"enum": ["up", "down", "left", "right"]
|
|
684
|
+
},
|
|
685
|
+
"distance": { "type": "number", "minimum": 1 },
|
|
686
|
+
"duration_ms": { "type": "integer", "minimum": 1 },
|
|
687
|
+
"timeout_ms": { "type": "integer", "minimum": 1 },
|
|
688
|
+
"settle": { "type": "boolean" }
|
|
689
|
+
},
|
|
690
|
+
"required": ["target", "direction", "distance", "duration_ms"],
|
|
691
|
+
"additionalProperties": false
|
|
692
|
+
},
|
|
693
|
+
"examples": [
|
|
694
|
+
{
|
|
695
|
+
"action": "ui.swipe",
|
|
696
|
+
"target": "example-scrollable",
|
|
697
|
+
"direction": "up",
|
|
698
|
+
"distance": 240,
|
|
699
|
+
"duration_ms": 300,
|
|
700
|
+
"intent": "Swipe the requested visible surface.",
|
|
701
|
+
"next": "done"
|
|
702
|
+
}
|
|
703
|
+
]
|
|
704
|
+
},
|
|
705
|
+
"ui.pan": {
|
|
706
|
+
"description": "Pan through a continuous pointer path from a test-id target or screen coordinates through the shared browser UI transport.",
|
|
707
|
+
"schema": {
|
|
708
|
+
"type": "object",
|
|
709
|
+
"properties": {
|
|
710
|
+
"target": {
|
|
711
|
+
"type": ["string", "object"],
|
|
712
|
+
"properties": {
|
|
713
|
+
"x": { "type": "number" },
|
|
714
|
+
"y": { "type": "number" }
|
|
715
|
+
},
|
|
716
|
+
"required": ["x", "y"],
|
|
717
|
+
"additionalProperties": false
|
|
718
|
+
},
|
|
719
|
+
"path": {
|
|
720
|
+
"type": "array",
|
|
721
|
+
"minItems": 1,
|
|
722
|
+
"items": {
|
|
723
|
+
"type": "object",
|
|
724
|
+
"properties": {
|
|
725
|
+
"x": { "type": "number" },
|
|
726
|
+
"y": { "type": "number" }
|
|
727
|
+
},
|
|
728
|
+
"required": ["x", "y"],
|
|
729
|
+
"additionalProperties": false
|
|
730
|
+
}
|
|
731
|
+
},
|
|
732
|
+
"delta": {
|
|
733
|
+
"type": "object",
|
|
734
|
+
"properties": {
|
|
735
|
+
"x": { "type": "number" },
|
|
736
|
+
"y": { "type": "number" }
|
|
737
|
+
},
|
|
738
|
+
"required": ["x", "y"],
|
|
739
|
+
"additionalProperties": false
|
|
740
|
+
},
|
|
741
|
+
"duration_ms": { "type": "integer", "minimum": 1 },
|
|
742
|
+
"timeout_ms": { "type": "integer", "minimum": 1 },
|
|
743
|
+
"settle": { "type": "boolean" }
|
|
744
|
+
},
|
|
745
|
+
"required": ["target", "duration_ms"],
|
|
746
|
+
"additionalProperties": false
|
|
747
|
+
},
|
|
748
|
+
"examples": [
|
|
749
|
+
{
|
|
750
|
+
"action": "ui.pan",
|
|
751
|
+
"target": "example-surface",
|
|
752
|
+
"path": [{ "x": 40, "y": 10 }, { "x": 80, "y": 20 }],
|
|
753
|
+
"duration_ms": 400,
|
|
754
|
+
"intent": "Pan through the requested pointer path.",
|
|
755
|
+
"next": "done"
|
|
756
|
+
}
|
|
757
|
+
]
|
|
758
|
+
},
|
|
759
|
+
"ui.drag": {
|
|
760
|
+
"description": "Drag a test-id target or screen coordinate through the shared browser UI transport.",
|
|
761
|
+
"schema": {
|
|
762
|
+
"type": "object",
|
|
763
|
+
"properties": {
|
|
764
|
+
"target": {
|
|
765
|
+
"type": ["string", "object"],
|
|
766
|
+
"properties": {
|
|
767
|
+
"x": { "type": "number" },
|
|
768
|
+
"y": { "type": "number" }
|
|
769
|
+
},
|
|
770
|
+
"required": ["x", "y"],
|
|
771
|
+
"additionalProperties": false
|
|
772
|
+
},
|
|
773
|
+
"path": {
|
|
774
|
+
"type": "array",
|
|
775
|
+
"minItems": 1,
|
|
776
|
+
"items": {
|
|
777
|
+
"type": "object",
|
|
778
|
+
"properties": {
|
|
779
|
+
"x": { "type": "number" },
|
|
780
|
+
"y": { "type": "number" }
|
|
781
|
+
},
|
|
782
|
+
"required": ["x", "y"],
|
|
783
|
+
"additionalProperties": false
|
|
784
|
+
}
|
|
785
|
+
},
|
|
786
|
+
"delta": {
|
|
787
|
+
"type": "object",
|
|
788
|
+
"properties": {
|
|
789
|
+
"x": { "type": "number" },
|
|
790
|
+
"y": { "type": "number" }
|
|
791
|
+
},
|
|
792
|
+
"required": ["x", "y"],
|
|
793
|
+
"additionalProperties": false
|
|
794
|
+
},
|
|
795
|
+
"duration_ms": { "type": "integer", "minimum": 1 },
|
|
796
|
+
"timeout_ms": { "type": "integer", "minimum": 1 },
|
|
797
|
+
"settle": { "type": "boolean" }
|
|
798
|
+
},
|
|
799
|
+
"required": ["target", "duration_ms"],
|
|
800
|
+
"additionalProperties": false
|
|
801
|
+
},
|
|
802
|
+
"examples": [
|
|
803
|
+
{
|
|
804
|
+
"action": "ui.drag",
|
|
805
|
+
"target": "example-slider",
|
|
806
|
+
"delta": { "x": 120, "y": 0 },
|
|
807
|
+
"duration_ms": 500,
|
|
808
|
+
"intent": "Drag the requested control to a new value.",
|
|
809
|
+
"next": "done"
|
|
810
|
+
}
|
|
811
|
+
]
|
|
812
|
+
},
|
|
813
|
+
"ui.long_press": {
|
|
814
|
+
"description": "Hold a test-id target or screen coordinate through the shared browser UI transport.",
|
|
815
|
+
"schema": {
|
|
816
|
+
"type": "object",
|
|
817
|
+
"properties": {
|
|
818
|
+
"target": {
|
|
819
|
+
"type": ["string", "object"],
|
|
820
|
+
"properties": {
|
|
821
|
+
"x": { "type": "number" },
|
|
822
|
+
"y": { "type": "number" }
|
|
823
|
+
},
|
|
824
|
+
"required": ["x", "y"],
|
|
825
|
+
"additionalProperties": false
|
|
826
|
+
},
|
|
827
|
+
"hold_ms": { "type": "integer", "minimum": 1 },
|
|
828
|
+
"timeout_ms": { "type": "integer", "minimum": 1 },
|
|
829
|
+
"settle": { "type": "boolean" }
|
|
830
|
+
},
|
|
831
|
+
"required": ["target", "hold_ms"],
|
|
832
|
+
"additionalProperties": false
|
|
833
|
+
},
|
|
834
|
+
"examples": [
|
|
835
|
+
{
|
|
836
|
+
"action": "ui.long_press",
|
|
837
|
+
"target": "example-control",
|
|
838
|
+
"hold_ms": 700,
|
|
839
|
+
"intent": "Hold the requested visible control.",
|
|
840
|
+
"next": "done"
|
|
841
|
+
}
|
|
842
|
+
]
|
|
843
|
+
},
|
|
667
844
|
"ui.wait_for": {
|
|
668
845
|
"description": "Wait for a UI condition through the Extension CDP adapter.",
|
|
669
846
|
"schema": {
|
|
@@ -763,6 +940,27 @@
|
|
|
763
940
|
"additionalProperties": false
|
|
764
941
|
}
|
|
765
942
|
},
|
|
943
|
+
"ui.capture_surface": {
|
|
944
|
+
"description": "Capture the complete current browser page as one registered PNG while leaving ui.screenshot viewport-only.",
|
|
945
|
+
"schema": {
|
|
946
|
+
"type": "object",
|
|
947
|
+
"properties": {
|
|
948
|
+
"path": { "type": "string" },
|
|
949
|
+
"label": { "type": "string" },
|
|
950
|
+
"category": { "type": "string" },
|
|
951
|
+
"timeout_ms": { "type": "number" }
|
|
952
|
+
},
|
|
953
|
+
"additionalProperties": false
|
|
954
|
+
},
|
|
955
|
+
"examples": [
|
|
956
|
+
{
|
|
957
|
+
"action": "ui.capture_surface",
|
|
958
|
+
"path": "screenshots/full-page.png",
|
|
959
|
+
"intent": "Preserve the complete page context for human review.",
|
|
960
|
+
"next": "done"
|
|
961
|
+
}
|
|
962
|
+
]
|
|
963
|
+
},
|
|
766
964
|
"app.status": {
|
|
767
965
|
"description": "Report the adapter's static status — platform, project root, resolved checkout shape, and headless compatibility mode (no live route or account).",
|
|
768
966
|
"examples": [
|
|
@@ -2982,8 +3180,13 @@
|
|
|
2982
3180
|
"ui.key_press",
|
|
2983
3181
|
"ui.set_input",
|
|
2984
3182
|
"ui.scroll",
|
|
3183
|
+
"ui.swipe",
|
|
3184
|
+
"ui.pan",
|
|
3185
|
+
"ui.drag",
|
|
3186
|
+
"ui.long_press",
|
|
2985
3187
|
"ui.wait_for",
|
|
2986
|
-
"ui.screenshot"
|
|
3188
|
+
"ui.screenshot",
|
|
3189
|
+
"ui.capture_surface"
|
|
2987
3190
|
]
|
|
2988
3191
|
},
|
|
2989
3192
|
{
|
|
@@ -2995,8 +3198,13 @@
|
|
|
2995
3198
|
"ui.key_press",
|
|
2996
3199
|
"ui.set_input",
|
|
2997
3200
|
"ui.scroll",
|
|
3201
|
+
"ui.swipe",
|
|
3202
|
+
"ui.pan",
|
|
3203
|
+
"ui.drag",
|
|
3204
|
+
"ui.long_press",
|
|
2998
3205
|
"ui.wait_for",
|
|
2999
|
-
"ui.screenshot"
|
|
3206
|
+
"ui.screenshot",
|
|
3207
|
+
"ui.capture_surface"
|
|
3000
3208
|
]
|
|
3001
3209
|
}
|
|
3002
3210
|
]
|
|
@@ -675,6 +675,185 @@
|
|
|
675
675
|
"additionalProperties": false
|
|
676
676
|
}
|
|
677
677
|
},
|
|
678
|
+
"ui.swipe": {
|
|
679
|
+
"description": "Swipe from a test-id target or screen coordinates in one cardinal direction through the shared native UI provider.",
|
|
680
|
+
"schema": {
|
|
681
|
+
"type": "object",
|
|
682
|
+
"properties": {
|
|
683
|
+
"target": {
|
|
684
|
+
"type": ["string", "object"],
|
|
685
|
+
"properties": {
|
|
686
|
+
"x": { "type": "number" },
|
|
687
|
+
"y": { "type": "number" }
|
|
688
|
+
},
|
|
689
|
+
"required": ["x", "y"],
|
|
690
|
+
"additionalProperties": false
|
|
691
|
+
},
|
|
692
|
+
"direction": {
|
|
693
|
+
"type": "string",
|
|
694
|
+
"enum": ["up", "down", "left", "right"]
|
|
695
|
+
},
|
|
696
|
+
"distance": { "type": "number", "minimum": 1 },
|
|
697
|
+
"duration_ms": { "type": "integer", "minimum": 1 },
|
|
698
|
+
"timeout_ms": { "type": "integer", "minimum": 1 },
|
|
699
|
+
"settle": { "type": "boolean" }
|
|
700
|
+
},
|
|
701
|
+
"required": ["target", "direction", "distance", "duration_ms"],
|
|
702
|
+
"additionalProperties": false
|
|
703
|
+
},
|
|
704
|
+
"examples": [
|
|
705
|
+
{
|
|
706
|
+
"action": "ui.swipe",
|
|
707
|
+
"target": "example-scrollable",
|
|
708
|
+
"direction": "up",
|
|
709
|
+
"distance": 240,
|
|
710
|
+
"duration_ms": 300,
|
|
711
|
+
"intent": "Swipe the requested visible surface.",
|
|
712
|
+
"next": "done"
|
|
713
|
+
}
|
|
714
|
+
]
|
|
715
|
+
},
|
|
716
|
+
"ui.pan": {
|
|
717
|
+
"description": "Pan from a test-id target or screen coordinates through the shared native UI provider.",
|
|
718
|
+
"schema": {
|
|
719
|
+
"type": "object",
|
|
720
|
+
"properties": {
|
|
721
|
+
"target": {
|
|
722
|
+
"type": ["string", "object"],
|
|
723
|
+
"properties": {
|
|
724
|
+
"x": { "type": "number" },
|
|
725
|
+
"y": { "type": "number" }
|
|
726
|
+
},
|
|
727
|
+
"required": ["x", "y"],
|
|
728
|
+
"additionalProperties": false
|
|
729
|
+
},
|
|
730
|
+
"path": {
|
|
731
|
+
"type": "array",
|
|
732
|
+
"minItems": 1,
|
|
733
|
+
"maxItems": 1,
|
|
734
|
+
"items": {
|
|
735
|
+
"type": "object",
|
|
736
|
+
"properties": {
|
|
737
|
+
"x": { "type": "number" },
|
|
738
|
+
"y": { "type": "number" }
|
|
739
|
+
},
|
|
740
|
+
"required": ["x", "y"],
|
|
741
|
+
"additionalProperties": false
|
|
742
|
+
}
|
|
743
|
+
},
|
|
744
|
+
"delta": {
|
|
745
|
+
"type": "object",
|
|
746
|
+
"properties": {
|
|
747
|
+
"x": { "type": "number" },
|
|
748
|
+
"y": { "type": "number" }
|
|
749
|
+
},
|
|
750
|
+
"required": ["x", "y"],
|
|
751
|
+
"additionalProperties": false
|
|
752
|
+
},
|
|
753
|
+
"duration_ms": { "type": "integer", "minimum": 1 },
|
|
754
|
+
"timeout_ms": { "type": "integer", "minimum": 1 },
|
|
755
|
+
"settle": { "type": "boolean" }
|
|
756
|
+
},
|
|
757
|
+
"required": ["target", "duration_ms"],
|
|
758
|
+
"additionalProperties": false
|
|
759
|
+
},
|
|
760
|
+
"examples": [
|
|
761
|
+
{
|
|
762
|
+
"action": "ui.pan",
|
|
763
|
+
"target": "example-surface",
|
|
764
|
+
"path": [{ "x": 80, "y": 20 }],
|
|
765
|
+
"duration_ms": 400,
|
|
766
|
+
"intent": "Pan through the requested pointer path.",
|
|
767
|
+
"next": "done"
|
|
768
|
+
}
|
|
769
|
+
]
|
|
770
|
+
},
|
|
771
|
+
"ui.drag": {
|
|
772
|
+
"description": "Drag a test-id target or screen coordinate through the shared native UI provider.",
|
|
773
|
+
"schema": {
|
|
774
|
+
"type": "object",
|
|
775
|
+
"properties": {
|
|
776
|
+
"target": {
|
|
777
|
+
"type": ["string", "object"],
|
|
778
|
+
"properties": {
|
|
779
|
+
"x": { "type": "number" },
|
|
780
|
+
"y": { "type": "number" }
|
|
781
|
+
},
|
|
782
|
+
"required": ["x", "y"],
|
|
783
|
+
"additionalProperties": false
|
|
784
|
+
},
|
|
785
|
+
"path": {
|
|
786
|
+
"type": "array",
|
|
787
|
+
"minItems": 1,
|
|
788
|
+
"maxItems": 1,
|
|
789
|
+
"items": {
|
|
790
|
+
"type": "object",
|
|
791
|
+
"properties": {
|
|
792
|
+
"x": { "type": "number" },
|
|
793
|
+
"y": { "type": "number" }
|
|
794
|
+
},
|
|
795
|
+
"required": ["x", "y"],
|
|
796
|
+
"additionalProperties": false
|
|
797
|
+
}
|
|
798
|
+
},
|
|
799
|
+
"delta": {
|
|
800
|
+
"type": "object",
|
|
801
|
+
"properties": {
|
|
802
|
+
"x": { "type": "number" },
|
|
803
|
+
"y": { "type": "number" }
|
|
804
|
+
},
|
|
805
|
+
"required": ["x", "y"],
|
|
806
|
+
"additionalProperties": false
|
|
807
|
+
},
|
|
808
|
+
"duration_ms": { "type": "integer", "minimum": 1 },
|
|
809
|
+
"timeout_ms": { "type": "integer", "minimum": 1 },
|
|
810
|
+
"settle": { "type": "boolean" }
|
|
811
|
+
},
|
|
812
|
+
"required": ["target", "duration_ms"],
|
|
813
|
+
"additionalProperties": false
|
|
814
|
+
},
|
|
815
|
+
"examples": [
|
|
816
|
+
{
|
|
817
|
+
"action": "ui.drag",
|
|
818
|
+
"target": "example-slider",
|
|
819
|
+
"delta": { "x": 120, "y": 0 },
|
|
820
|
+
"duration_ms": 500,
|
|
821
|
+
"intent": "Drag the requested control to a new value.",
|
|
822
|
+
"next": "done"
|
|
823
|
+
}
|
|
824
|
+
]
|
|
825
|
+
},
|
|
826
|
+
"ui.long_press": {
|
|
827
|
+
"description": "Hold a test-id target or screen coordinate through the shared native UI provider.",
|
|
828
|
+
"schema": {
|
|
829
|
+
"type": "object",
|
|
830
|
+
"properties": {
|
|
831
|
+
"target": {
|
|
832
|
+
"type": ["string", "object"],
|
|
833
|
+
"properties": {
|
|
834
|
+
"x": { "type": "number" },
|
|
835
|
+
"y": { "type": "number" }
|
|
836
|
+
},
|
|
837
|
+
"required": ["x", "y"],
|
|
838
|
+
"additionalProperties": false
|
|
839
|
+
},
|
|
840
|
+
"hold_ms": { "type": "integer", "minimum": 1 },
|
|
841
|
+
"timeout_ms": { "type": "integer", "minimum": 1 },
|
|
842
|
+
"settle": { "type": "boolean" }
|
|
843
|
+
},
|
|
844
|
+
"required": ["target", "hold_ms"],
|
|
845
|
+
"additionalProperties": false
|
|
846
|
+
},
|
|
847
|
+
"examples": [
|
|
848
|
+
{
|
|
849
|
+
"action": "ui.long_press",
|
|
850
|
+
"target": "example-control",
|
|
851
|
+
"hold_ms": 700,
|
|
852
|
+
"intent": "Hold the requested visible control.",
|
|
853
|
+
"next": "done"
|
|
854
|
+
}
|
|
855
|
+
]
|
|
856
|
+
},
|
|
678
857
|
"ui.wait_for": {
|
|
679
858
|
"description": "Wait for a mounted React Native testID/test_id. Optional text validates text returned by that testID; text alone is not supported on Mobile.",
|
|
680
859
|
"schema": {
|
|
@@ -781,6 +960,31 @@
|
|
|
781
960
|
"additionalProperties": false
|
|
782
961
|
}
|
|
783
962
|
},
|
|
963
|
+
"ui.capture_surface": {
|
|
964
|
+
"description": "Capture the complete current native scroll surface as one registered PNG while leaving ui.screenshot viewport-only.",
|
|
965
|
+
"schema": {
|
|
966
|
+
"type": "object",
|
|
967
|
+
"properties": {
|
|
968
|
+
"path": { "type": "string" },
|
|
969
|
+
"label": { "type": "string" },
|
|
970
|
+
"surface_test_id": { "type": "string" },
|
|
971
|
+
"until_test_id": { "type": "string" },
|
|
972
|
+
"max_scrolls": { "type": "integer", "minimum": 1 },
|
|
973
|
+
"restore_position": { "type": "boolean" }
|
|
974
|
+
},
|
|
975
|
+
"additionalProperties": false
|
|
976
|
+
},
|
|
977
|
+
"examples": [
|
|
978
|
+
{
|
|
979
|
+
"action": "ui.capture_surface",
|
|
980
|
+
"path": "screenshots/full-screen.png",
|
|
981
|
+
"surface_test_id": "screen-scroll-surface",
|
|
982
|
+
"until_test_id": "screen-bottom",
|
|
983
|
+
"intent": "Preserve the complete scrollable context for human review.",
|
|
984
|
+
"next": "done"
|
|
985
|
+
}
|
|
986
|
+
]
|
|
987
|
+
},
|
|
784
988
|
"app.lifecycle": {
|
|
785
989
|
"description": "Drive outer mobile app lifecycle for deterministic performance start states without rebuilding: foreground/launch, background, terminate, or restart the installed app.",
|
|
786
990
|
"examples": [
|
|
@@ -3101,7 +3305,12 @@
|
|
|
3101
3305
|
"metamask.deeplink.open",
|
|
3102
3306
|
"ui.navigate",
|
|
3103
3307
|
"ui.press",
|
|
3308
|
+
"ui.swipe",
|
|
3309
|
+
"ui.pan",
|
|
3310
|
+
"ui.drag",
|
|
3311
|
+
"ui.long_press",
|
|
3104
3312
|
"ui.screenshot",
|
|
3313
|
+
"ui.capture_surface",
|
|
3105
3314
|
"ui.scroll",
|
|
3106
3315
|
"ui.set_input",
|
|
3107
3316
|
"ui.wait_for"
|
|
@@ -3113,7 +3322,12 @@
|
|
|
3113
3322
|
"metamask.deeplink.open",
|
|
3114
3323
|
"ui.navigate",
|
|
3115
3324
|
"ui.press",
|
|
3325
|
+
"ui.swipe",
|
|
3326
|
+
"ui.pan",
|
|
3327
|
+
"ui.drag",
|
|
3328
|
+
"ui.long_press",
|
|
3116
3329
|
"ui.screenshot",
|
|
3330
|
+
"ui.capture_surface",
|
|
3117
3331
|
"ui.scroll",
|
|
3118
3332
|
"ui.set_input",
|
|
3119
3333
|
"ui.wait_for"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeeed/metamask-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mm-harness": "bin/mm-harness"
|
|
@@ -20,10 +20,12 @@
|
|
|
20
20
|
"check:syntax": "find . -name '*.mjs' -print0 | xargs -0 -n1 node --check"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@farmslot/agent-runtime": "0.
|
|
23
|
+
"@farmslot/agent-runtime": "0.7.0",
|
|
24
|
+
"@farmslot/expo-recipe": "0.7.1",
|
|
24
25
|
"@farmslot/handoff": "^0.3.1",
|
|
25
|
-
"@farmslot/protocol": "0.
|
|
26
|
-
"@farmslot/recipe-harness": "0.
|
|
26
|
+
"@farmslot/protocol": "0.18.0",
|
|
27
|
+
"@farmslot/recipe-harness": "0.14.0",
|
|
28
|
+
"agent-device": "0.19.3",
|
|
27
29
|
"commander": "^12.0.0",
|
|
28
30
|
"es-module-lexer": "2.3.1",
|
|
29
31
|
"esbuild": "0.28.1",
|
|
File without changes
|
|
File without changes
|
/package/library/recipes/{perps/read-markets.core.recipe.json → core/perps/read-markets.recipe.json}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/library/recipes/{perps/smoke.extension.recipe.json → extension/perps/smoke.recipe.json}
RENAMED
|
File without changes
|
|
File without changes
|
/package/library/recipes/{runner/smoke.extension.recipe.json → extension/runner/smoke.recipe.json}
RENAMED
|
File without changes
|
/package/library/recipes/{wallet/smoke.extension.recipe.json → extension/wallet/smoke.recipe.json}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/library/recipes/{runner/smoke.mobile.recipe.json → mobile/runner/smoke.recipe.json}
RENAMED
|
File without changes
|
/package/library/recipes/{wallet/smoke.mobile.recipe.json → mobile/wallet/smoke.recipe.json}
RENAMED
|
File without changes
|