@deeeed/metamask-harness 0.2.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 +161 -0
- package/README.md +140 -0
- package/bin/mm-harness +99 -0
- package/docs/CHEATSHEET.md +61 -0
- package/docs/CLI-SPEC.md +915 -0
- package/docs/MENTAL-MODEL.md +295 -0
- package/docs/architecture.md +367 -0
- package/docs/extension-runtime-commands.md +60 -0
- package/docs/harness-cli.md +43 -0
- package/docs/live-adapter-contract.md +188 -0
- package/docs/package-boundaries.md +47 -0
- package/docs/perps-flow-catalog.md +235 -0
- package/docs/recipe-libraries.md +95 -0
- package/docs/runtime-file-conventions.md +36 -0
- package/library/actions/core/perps/_controller.mjs +727 -0
- package/library/actions/core/perps/assert_orders.mjs +53 -0
- package/library/actions/core/perps/assert_positions.mjs +52 -0
- package/library/actions/core/perps/close_orders.mjs +97 -0
- package/library/actions/core/perps/close_positions.mjs +118 -0
- package/library/actions/core/perps/ensure_orders.mjs +40 -0
- package/library/actions/core/perps/ensure_positions.mjs +37 -0
- package/library/actions/core/perps/place_order.mjs +201 -0
- package/library/actions/core/perps/read_account.mjs +30 -0
- package/library/actions/core/perps/read_orders.mjs +27 -0
- package/library/actions/core/perps/read_positions.mjs +27 -0
- package/library/actions/core/perps/start_state.mjs +92 -0
- package/library/actions/core/perps/teardown_state.mjs +86 -0
- package/library/actions/extension/perps/assert_orders.mjs +11 -0
- package/library/actions/extension/perps/assert_positions.mjs +11 -0
- package/library/actions/extension/perps/close_orders.mjs +8 -0
- package/library/actions/extension/perps/close_positions.mjs +8 -0
- package/library/actions/extension/perps/ensure_orders.mjs +4 -0
- package/library/actions/extension/perps/ensure_positions.mjs +4 -0
- package/library/actions/extension/perps/perps.mjs +730 -0
- package/library/actions/extension/perps/place_order.mjs +7 -0
- package/library/actions/extension/perps/read_orders.mjs +4 -0
- package/library/actions/extension/perps/read_positions.mjs +3 -0
- package/library/actions/extension/platform/cdp.mjs +541 -0
- package/library/actions/extension/ui/navigate.mjs +44 -0
- package/library/actions/extension/wallet/ensure_unlocked.mjs +36 -0
- package/library/actions/extension/wallet/read_state.mjs +27 -0
- package/library/actions/extension/wallet/select_account.mjs +48 -0
- package/library/actions/extension/wallet/setup.mjs +35 -0
- package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +185 -0
- package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +1662 -0
- package/library/actions/mobile/bridge-runtime/cdp-bridge.cjs +686 -0
- package/library/actions/mobile/bridge-runtime/lib/cdp-eval.cjs +110 -0
- package/library/actions/mobile/bridge-runtime/lib/config.cjs +39 -0
- package/library/actions/mobile/bridge-runtime/lib/issue-capture.cjs +446 -0
- package/library/actions/mobile/bridge-runtime/lib/target-discovery.cjs +204 -0
- package/library/actions/mobile/bridge-runtime/lib/ws-client.cjs +108 -0
- package/library/actions/mobile/bridge-runtime/setup-wallet.sh +442 -0
- package/library/actions/mobile/perps/assert_orders.mjs +11 -0
- package/library/actions/mobile/perps/assert_positions.mjs +11 -0
- package/library/actions/mobile/perps/close_orders.mjs +8 -0
- package/library/actions/mobile/perps/close_positions.mjs +8 -0
- package/library/actions/mobile/perps/ensure_orders.mjs +4 -0
- package/library/actions/mobile/perps/ensure_positions.mjs +4 -0
- package/library/actions/mobile/perps/perps.mjs +709 -0
- package/library/actions/mobile/perps/place_order.mjs +7 -0
- package/library/actions/mobile/perps/read_orders.mjs +4 -0
- package/library/actions/mobile/perps/read_positions.mjs +3 -0
- package/library/actions/mobile/platform/bridge.mjs +283 -0
- package/library/actions/mobile/ui/navigate.mjs +38 -0
- package/library/actions/mobile/wallet/ensure_unlocked.mjs +107 -0
- package/library/actions/mobile/wallet/home.mjs +35 -0
- package/library/actions/mobile/wallet/read_state.mjs +40 -0
- package/library/actions/mobile/wallet/select_account.mjs +48 -0
- package/library/actions/mobile/wallet/setup.mjs +220 -0
- package/library/flows/perps.flows.json +64 -0
- package/library/library.json +7 -0
- package/library/manifests/core.action-manifest.json +1282 -0
- package/library/manifests/extension.action-manifest.json +1749 -0
- package/library/manifests/mobile.action-manifest.json +1753 -0
- package/library/recipes/action-validation.extension.recipe.json +417 -0
- package/library/recipes/action-validation.mobile.recipe.json +422 -0
- package/library/recipes/order-lifecycle.core.recipe.json +78 -0
- package/library/recipes/perps-lifecycle.recipe.json +194 -0
- package/library/recipes/read-markets.core.recipe.json +38 -0
- package/library/recipes/smoke.extension.recipe.json +31 -0
- package/library/recipes/smoke.mobile.recipe.json +31 -0
- package/library/recipes/trading-lifecycle.core.recipe.json +76 -0
- package/orchestration/compat-overlays/README.md +19 -0
- package/orchestration/compat-overlays/mobile/README.md +13 -0
- package/orchestration/compat-overlays/mobile/rn81-message-event-source.patch +42 -0
- package/orchestration/core/cleanup.sh +37 -0
- package/orchestration/core/inject.sh +154 -0
- package/orchestration/doctor.mjs +72 -0
- package/orchestration/extension/cleanup.mjs +60 -0
- package/orchestration/extension/console-tail.mjs +228 -0
- package/orchestration/extension/ensure-browser.sh +416 -0
- package/orchestration/extension/ensure-ready.ts +185 -0
- package/orchestration/extension/extension-id.ts +107 -0
- package/orchestration/extension/inject.mjs +266 -0
- package/orchestration/extension/launch-browser.cjs +216 -0
- package/orchestration/extension/launch.sh +175 -0
- package/orchestration/extension/live.sh +320 -0
- package/orchestration/extension/pin-remote-flags.cjs +45 -0
- package/orchestration/extension/readiness.mjs +414 -0
- package/orchestration/extension/refresh-build.sh +190 -0
- package/orchestration/extension/runtime-decision.ts +445 -0
- package/orchestration/extension/runtime.ts +407 -0
- package/orchestration/extension/seed-fixture.sh +177 -0
- package/orchestration/extension/sidepanel-toggle.sh +291 -0
- package/orchestration/extension/snapshot-dist.sh +84 -0
- package/orchestration/extension/start-watch.sh +339 -0
- package/orchestration/extension/wallet-fixture-state.cjs +1086 -0
- package/orchestration/lib/activate-repo-node.sh +144 -0
- package/orchestration/lib/cli-color.mjs +84 -0
- package/orchestration/lib/cli-commands.mjs +243 -0
- package/orchestration/lib/cli-home.mjs +354 -0
- package/orchestration/lib/cli-ux.sh +252 -0
- package/orchestration/lib/cli-version.mjs +123 -0
- package/orchestration/lib/ensure-runner-deps.sh +56 -0
- package/orchestration/lib/harness-path.sh +55 -0
- package/orchestration/lib/hash-helpers.sh +44 -0
- package/orchestration/lib/json-field.sh +23 -0
- package/orchestration/lib/log-tui.mjs +304 -0
- package/orchestration/lib/open-debug.mjs +317 -0
- package/orchestration/lib/path-defaults.json +4 -0
- package/orchestration/lib/progress.mjs +107 -0
- package/orchestration/lib/recipe-paths.mjs +26 -0
- package/orchestration/lib/resolve-farmslot-ports.sh +144 -0
- package/orchestration/manifest.json +358 -0
- package/orchestration/mobile/cleanup.sh +192 -0
- package/orchestration/mobile/deps-markers.ts +21 -0
- package/orchestration/mobile/inject.sh +681 -0
- package/orchestration/mobile/launch.sh +137 -0
- package/orchestration/mobile/live.sh +125 -0
- package/orchestration/mobile/runtime-decision.ts +292 -0
- package/orchestration/porcelain/metamask-recipe +99 -0
- package/orchestration/porcelain/mm-recipe +1591 -0
- package/orchestration/porcelain/mme-recipe +1181 -0
- package/package.json +59 -0
- package/runner/extension/verify.sh +511 -0
- package/runner/mobile/verify.sh +501 -0
- package/runner/src/adapters.ts +601 -0
- package/runner/src/cli.ts +1820 -0
- package/runner/src/commands/debug.ts +44 -0
- package/runner/src/commands/fixtures.ts +99 -0
- package/runner/src/commands/launch.ts +397 -0
- package/runner/src/commands/logs.ts +60 -0
- package/runner/src/commands/shared.ts +138 -0
- package/runner/src/completions-cache.ts +86 -0
- package/runner/src/doctor.ts +203 -0
- package/runner/src/harness.ts +516 -0
- package/runner/src/heal-bounds.ts +179 -0
- package/runner/src/index.ts +6 -0
- package/runner/src/live-adapter-contract.ts +274 -0
- package/runner/src/manifest.ts +47 -0
- package/runner/src/mm-harness-cli.ts +488 -0
- package/runner/src/paths.ts +198 -0
- package/runner/src/recording-target.ts +147 -0
- package/runner/src/run-recording.ts +329 -0
- package/runner/src/runner.ts +108 -0
- package/runner/src/types.ts +57 -0
- package/scripts/completions.sh +125 -0
- package/scripts/install-completions.sh +62 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Package Boundaries
|
|
2
|
+
|
|
3
|
+
This package intentionally stays as **one npm package** with a clear internal
|
|
4
|
+
split. Splitting into two packages now would make users choose between packages
|
|
5
|
+
before the runtime API is stable. Instead, keep one install surface and separate
|
|
6
|
+
responsibilities inside the repo.
|
|
7
|
+
|
|
8
|
+
## Internal split
|
|
9
|
+
|
|
10
|
+
| Area | Owns | Does not own |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Recipe layer | Action manifests, reusable recipes, typed runner binding, Mobile/Extension live adapters, proof semantics. | Starting Metro/Chrome, simulator boot, native builds, git cleanup. |
|
|
13
|
+
| Runtime lifecycle layer | Harness install/cleanup, Metro/dev-client launch, bundle prewarm, Chrome/CDP launch, fixture/profile setup, readiness gates. | Recipe graph execution, action vocabulary decisions, task-specific proof logic. |
|
|
14
|
+
|
|
15
|
+
## Stable command contract
|
|
16
|
+
|
|
17
|
+
Keep the public package simple:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
mm-harness launch ios ... # runtime lifecycle, then readiness proof (mobile)
|
|
21
|
+
mm-harness launch ... # runtime lifecycle, then readiness proof (extension)
|
|
22
|
+
mm-harness run <recipe.json> ... # recipe execution only
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Wrappers such as skills or slot farms should call those commands. They should not
|
|
26
|
+
copy adapter scripts or reimplement Metro/Chrome launch behavior.
|
|
27
|
+
|
|
28
|
+
## Why not two packages yet?
|
|
29
|
+
|
|
30
|
+
A future split may be useful, for example:
|
|
31
|
+
|
|
32
|
+
- `@metamask/recipe-runner` for manifests/adapters/proof execution;
|
|
33
|
+
- `@metamask/recipe-runtime` for Mobile/Extension sandbox launch.
|
|
34
|
+
|
|
35
|
+
Do that only after the runtime CLI is stable, all wrappers call it exclusively
|
|
36
|
+
(no copied adapter scripts), and the two areas have gone several releases
|
|
37
|
+
without a change that touches both. Until then, two packages would likely
|
|
38
|
+
increase confusion and version skew.
|
|
39
|
+
|
|
40
|
+
## Change discipline
|
|
41
|
+
|
|
42
|
+
1. Prefer moving behavior into the runner before changing farms/skills.
|
|
43
|
+
2. Keep compatibility wrappers when renaming files or commands.
|
|
44
|
+
3. Validate both paths after runtime changes:
|
|
45
|
+
- direct runner/skill path;
|
|
46
|
+
- Farmslot/Command Center prepare path.
|
|
47
|
+
4. Do not move files just for tidiness if callers still depend on old paths.
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Perps Flow Catalog
|
|
2
|
+
|
|
3
|
+
MetaMask Perps recipes use a small set of parameterized primitives plus higher-level `ensure_*` wrappers. Do not add one action per scenario. A new Perps capability should first try to extend selector params or flow params.
|
|
4
|
+
|
|
5
|
+
## Layers
|
|
6
|
+
|
|
7
|
+
| Layer | Examples | Responsibility |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Read primitives | `metamask.perps.read_positions`, `metamask.perps.read_orders` | Return redacted live state for a selected subset. |
|
|
10
|
+
| Bulk mutation primitives | `metamask.perps.close_positions`, `metamask.perps.close_orders`, `metamask.perps.place_order` | Perform one real product operation over a parameterized selection. |
|
|
11
|
+
| Assertion wrappers | `metamask.perps.assert_positions`, `metamask.perps.assert_orders` | Read live state and fail when selected state does not match expectation. |
|
|
12
|
+
| Ensure wrappers | `metamask.perps.ensure_positions`, `metamask.perps.ensure_orders` | Compose read/mutate/assert to create idempotent start states. |
|
|
13
|
+
| Domain setup/teardown | `metamask.perps.start_state`, `metamask.perps.teardown_state` | Compose wallet/provider/network/page/position/order setup before a proof window. |
|
|
14
|
+
|
|
15
|
+
## Selection contract
|
|
16
|
+
|
|
17
|
+
Position/order operations accept the same selector shape:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"action": "metamask.perps.close_positions",
|
|
22
|
+
"mode": "matching",
|
|
23
|
+
"markets": ["BTC", "ETH"],
|
|
24
|
+
"side": "long",
|
|
25
|
+
"timeout_ms": 30000
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- `mode: "matching"` selects `market`/`symbol` or `markets`/`symbols`.
|
|
30
|
+
- `mode: "all"` selects every live position/order returned by the product.
|
|
31
|
+
- `side` narrows selection when the product returns side information.
|
|
32
|
+
- `selector` can carry the same fields when a nested shape is easier for flow composition.
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
Close every live Perps position before a proof window:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{ "action": "metamask.perps.close_positions", "mode": "all" }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Cancel only BTC open orders:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{ "action": "metamask.perps.close_orders", "market": "BTC" }
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Higher-level clean start state:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"action": "metamask.perps.ensure_positions",
|
|
53
|
+
"state": "none",
|
|
54
|
+
"mode": "all"
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Provider/network setup belongs in a configurable start-state contract such as `metamask.perps.start_state`, not in duplicate primitive actions:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"flow": "metamask.perps.start_state",
|
|
63
|
+
"params": {
|
|
64
|
+
"provider": "hyperliquid",
|
|
65
|
+
"network": "testnet",
|
|
66
|
+
"page": "market",
|
|
67
|
+
"market": "BTC",
|
|
68
|
+
"positions": { "state": "none", "mode": "all" },
|
|
69
|
+
"orders": { "state": "none", "mode": "all" }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Position update operations
|
|
75
|
+
|
|
76
|
+
Perps needs more than open/close. When TP/SL, margin, or leverage update coverage is added, prefer one parameterized position-update primitive instead of one adapter file per feature. The primitive should accept a position selector, a small set of update operations, and explicit assertions over the resulting position/order state.
|
|
77
|
+
|
|
78
|
+
That future primitive should compose controller-backed product APIs when that is the supported app path. It must not mutate React/Redux/MobX/DOM/local storage directly.
|
|
79
|
+
|
|
80
|
+
## Direct controller usage
|
|
81
|
+
|
|
82
|
+
When a recipe genuinely needs direct controller access and there is no reusable UI-equivalent flow, the agent should call the product controller directly through the platform bridge/CDP capability documented for that project.
|
|
83
|
+
|
|
84
|
+
The runner should help by documenting discoverable controller capabilities, not by hiding them behind another action vocabulary. For each direct controller capability, document:
|
|
85
|
+
|
|
86
|
+
- controller/API path;
|
|
87
|
+
- supported params;
|
|
88
|
+
- whether it changes state;
|
|
89
|
+
- required preconditions;
|
|
90
|
+
- expected postcondition assertion;
|
|
91
|
+
- redaction rules for trace output.
|
|
92
|
+
|
|
93
|
+
Example documentation shape:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"capability": "PerpsController.setTpSl",
|
|
98
|
+
"access": "direct-controller",
|
|
99
|
+
"params": {
|
|
100
|
+
"market": "BTC",
|
|
101
|
+
"takeProfit": { "price": "72000" },
|
|
102
|
+
"stopLoss": { "price": "65000" }
|
|
103
|
+
},
|
|
104
|
+
"postcondition": {
|
|
105
|
+
"action": "metamask.perps.assert_orders",
|
|
106
|
+
"market": "BTC",
|
|
107
|
+
"state": "present"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
State-changing direct controller calls must still be followed by a read/assert step or by an `ensure_*` wrapper that proves the final state.
|
|
113
|
+
|
|
114
|
+
## Limiting live-adapter file count
|
|
115
|
+
|
|
116
|
+
Perps should converge to one domain dispatcher per platform, not one new file for every controller operation. The runner can still expose many manifest actions, but implementation should route through a small domain module:
|
|
117
|
+
|
|
118
|
+
```text
|
|
119
|
+
library/actions/mobile/perps/perps.mjs # shared Mobile Perps operation catalog
|
|
120
|
+
library/actions/extension/perps/perps.mjs # shared Extension Perps operation catalog
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Runner resolution supports a domain dispatcher fallback such as `library/actions/<platform>/perps/perps.mjs` when an action-specific file is absent. That keeps discoverability in the manifest while avoiding a growing pile of tiny wrapper files.
|
|
124
|
+
|
|
125
|
+
## Rule of thumb for adding adapter files
|
|
126
|
+
|
|
127
|
+
Add a named adapter/flow when it represents a reusable product workflow that normally has a UI path and would otherwise waste proof-video time on repetitive setup. Examples: unlock wallet, navigate to Perps, ensure provider/network, open a market, create a baseline position, close selected positions, cancel selected orders, or prepare an order form.
|
|
128
|
+
|
|
129
|
+
Do not add a new adapter file only because a controller exposes another method. For direct controller operations, document the real controller capability and params so the agent can call the product API directly when appropriate.
|
|
130
|
+
|
|
131
|
+
| Need | Preferred shape | Why |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| Faster setup for a visual proof with a matching UI/user workflow | named flow or semantic adapter, e.g. `ensure_positions`, `close_positions` | Keeps proof videos focused while still using supported app/API paths. |
|
|
134
|
+
| Direct product capability with many variants | documented direct controller capability + required postcondition | Avoids one file per controller method and avoids a useless wrapper vocabulary. |
|
|
135
|
+
| Ticket-specific visual claim | task-local recipe assertion/evidence | Avoids polluting the domain API with one-off checks. |
|
|
136
|
+
| Repeated domain baseline across teams | catalog flow such as `start_state` | Creates a stable starting contract for many recipes. |
|
|
137
|
+
|
|
138
|
+
Direct controller capabilities must still be discoverable in docs/manifest metadata. The metadata should describe the real controller/API path, required params, examples, postconditions, and whether the operation is state-changing. The agent should be able to infer valid direct calls without reverse-engineering app internals first.
|
|
139
|
+
|
|
140
|
+
## Preconditions vs prestate
|
|
141
|
+
|
|
142
|
+
Existing Mobile recipes use pre-conditions such as `wallet.unlocked`, `perps.feature_enabled`, `perps.ready_to_trade`, `perps.sufficient_balance`, `perps.open_position`, `perps.open_position_tpsl`, `perps.open_limit_order`, `perps.not_in_watchlist`, and `perps.trading_flag`.
|
|
143
|
+
|
|
144
|
+
Recipe v1 should keep the same concept, but split it into two different responsibilities:
|
|
145
|
+
|
|
146
|
+
| Concept | Mutates state? | Purpose | Examples |
|
|
147
|
+
|---|---:|---|---|
|
|
148
|
+
| `preconditions` / `requires` | No | Fast fail with actionable reason when the target cannot support the recipe. | `wallet.unlocked`, `perps.feature_enabled`, `perps.trading_flag` |
|
|
149
|
+
| `prestate` / `startState` | Yes, when needed | Converge the app to a configurable baseline before the proof window. | unlock, select account, choose network/provider, close positions/orders, open market |
|
|
150
|
+
|
|
151
|
+
A precondition should not repair state. It answers “is this environment eligible?” A prestate answers “make the environment look like this before the proof starts.”
|
|
152
|
+
|
|
153
|
+
## Recommended Perps base prestate
|
|
154
|
+
|
|
155
|
+
Most Perps recipes should inherit from a configurable base prestate instead of repeating setup inline:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"flow": "metamask.perps.start_state",
|
|
160
|
+
"params": {
|
|
161
|
+
"wallet": { "state": "unlocked", "account": "default" },
|
|
162
|
+
"featureFlags": { "perps": true, "trading": true },
|
|
163
|
+
"provider": "hyperliquid",
|
|
164
|
+
"network": "testnet",
|
|
165
|
+
"readyToTrade": true,
|
|
166
|
+
"balance": { "minWithdrawableUsd": "1" },
|
|
167
|
+
"page": "market",
|
|
168
|
+
"market": "BTC",
|
|
169
|
+
"positions": { "state": "none", "mode": "matching", "markets": ["BTC"] },
|
|
170
|
+
"orders": { "state": "none", "mode": "matching", "markets": ["BTC"] },
|
|
171
|
+
"hud": { "enabled": true, "proofSafe": true }
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
This flow should compose smaller actions/flows:
|
|
177
|
+
|
|
178
|
+
1. `metamask.wallet.ensure_unlocked`
|
|
179
|
+
2. `metamask.wallet.select_account` when requested
|
|
180
|
+
3. provider/network/testnet setup for Hyperliquid or another provider
|
|
181
|
+
4. read-only gates for feature/trading readiness
|
|
182
|
+
5. `metamask.perps.ensure_orders` for order baseline
|
|
183
|
+
6. `metamask.perps.ensure_positions` for position baseline
|
|
184
|
+
7. `ui.navigate` with a manifest-discoverable `page` alias, or raw route/hash fallback
|
|
185
|
+
8. `app.hud` when visual proof should show context and it will not obscure the claim
|
|
186
|
+
|
|
187
|
+
## Base prestate profiles
|
|
188
|
+
|
|
189
|
+
The runner should publish named profiles as examples, but keep them parameterized:
|
|
190
|
+
|
|
191
|
+
| Profile | Intended use | Default params |
|
|
192
|
+
|---|---|---|
|
|
193
|
+
| `perps.clean_market_testnet` | Most visual AC proofs from a clean market screen | Hyperliquid testnet, wallet unlocked, ready to trade, selected market, no selected positions/orders |
|
|
194
|
+
| `perps.open_position_testnet` | TP/SL, margin, close-position proofs | Hyperliquid testnet, selected market, one open position, optional side/notional/leverage |
|
|
195
|
+
| `perps.open_order_testnet` | Limit-order edit/cancel proofs | Hyperliquid testnet, selected market, one open order |
|
|
196
|
+
| `perps.provider_mainnet_readonly` | Read-only balance/provider proofs | Hyperliquid mainnet, no cleanup mutation unless explicitly requested |
|
|
197
|
+
|
|
198
|
+
Profiles are shortcuts, not separate hardcoded actions. A recipe should be able to override provider, network, market, account, positions, orders, balance, page, and HUD behavior.
|
|
199
|
+
|
|
200
|
+
## Recipe v1 shape
|
|
201
|
+
|
|
202
|
+
Recommended shape for a proof recipe:
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"preconditions": [
|
|
207
|
+
"wallet.unlocked",
|
|
208
|
+
"perps.feature_enabled",
|
|
209
|
+
"perps.trading_flag"
|
|
210
|
+
],
|
|
211
|
+
"startState": {
|
|
212
|
+
"action": "metamask.perps.start_state",
|
|
213
|
+
"intent": "Converge Perps to a clean BTC testnet baseline before proof",
|
|
214
|
+
"params": {
|
|
215
|
+
"profile": "perps.clean_market_testnet",
|
|
216
|
+
"market": "BTC",
|
|
217
|
+
"positions": { "state": "none", "market": "BTC" },
|
|
218
|
+
"orders": { "state": "none", "market": "BTC" }
|
|
219
|
+
},
|
|
220
|
+
"record": "trace_only"
|
|
221
|
+
},
|
|
222
|
+
"proof": {
|
|
223
|
+
"nodes": {
|
|
224
|
+
"ac-specific-step": {
|
|
225
|
+
"action": "ui.press",
|
|
226
|
+
"intent": "Perform the AC-specific Perps interaction through the UI",
|
|
227
|
+
"test_id": "example",
|
|
228
|
+
"record": "proof_window"
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
The prestate runs before the proof window and remains visible in `trace.json`/`summary.json`; the proof window only records the AC-specific behavior. This preserves review speed without hiding setup from the agent or reviewer.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Recipe Libraries
|
|
2
|
+
|
|
3
|
+
Per-change recipes are throwaway proofs: generated for one PR, run as evidence,
|
|
4
|
+
discarded. A **recipe library** is the durable keep behind them — the reusable
|
|
5
|
+
flows ("set up a funded wallet", "converge Perps to a clean BTC baseline") a
|
|
6
|
+
per-change recipe is composed FROM. Libraries are owned bottom-up: each
|
|
7
|
+
developer accumulates their own, teams share theirs, and this runner ships only
|
|
8
|
+
a minimal canonical set. Nothing here requires central governance to function.
|
|
9
|
+
|
|
10
|
+
## The three sources and who owns them
|
|
11
|
+
|
|
12
|
+
| Source | Location | Owned by | Contains |
|
|
13
|
+
| --- | --- | --- | --- |
|
|
14
|
+
| Personal | `<farmslot home>/recipe-library` (`FARMSLOT_HOME`, default `~/.farmslot`) | the developer, entirely | the developer's accumulated flow history |
|
|
15
|
+
| Team | a repo the team owns (any host); checked out locally and configured as a source | the team's developers directly — not a MetaMask-governed artifact | richer domain flows the team maintains |
|
|
16
|
+
| Canonical (repo-native) | this runner's `library/` | this runner | minimal, stable primitives only (see `library/flows/`) |
|
|
17
|
+
|
|
18
|
+
A library is just a directory:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
<library-root>/
|
|
22
|
+
library.json { "kind": "recipe-library", "schema_version": 1, "name": "..." }
|
|
23
|
+
flows/*.flows.json standard recipe-flow-catalog documents (Recipe Protocol v1 §8)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
There is no new format: library flows are the same flow-catalog documents a
|
|
27
|
+
recipe can reference through `uses`, and per-change recipes call them with the
|
|
28
|
+
standard `call` node.
|
|
29
|
+
|
|
30
|
+
## Resolution and precedence
|
|
31
|
+
|
|
32
|
+
`mm-harness run` resolves `call` refs from ordered sources; the first
|
|
33
|
+
source that declares a ref wins:
|
|
34
|
+
|
|
35
|
+
1. recipe-local declarations (inline `flows` and explicit `uses` paths) — always win;
|
|
36
|
+
2. your explicit entries: repeatable/colon-separated `--library name=path` or `RECIPE_LIBRARY_PATH` (order = precedence), or, when neither is set, your personal library;
|
|
37
|
+
3. the canonical `metamask` library, appended last.
|
|
38
|
+
|
|
39
|
+
Personal and team flows therefore shadow canonical ones **by default** — that
|
|
40
|
+
is intentional (your history is the point; the canonical set is fallback
|
|
41
|
+
vocabulary, not authority). Shadowing is never silent: it is printed at run
|
|
42
|
+
start, recorded in `summary.json` under `flowResolution`, and the exact
|
|
43
|
+
definitions a run executed are snapshotted into the `resolved-flows.json`
|
|
44
|
+
artifact so reviewers can inspect the evidence without access to your
|
|
45
|
+
libraries.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
mm-harness flows list # every flow across your sources, with provenance
|
|
49
|
+
RECIPE_LIBRARY_PATH="team=~/dev/team-recipes" mm-harness flows list
|
|
50
|
+
mm-harness run recipe.json --adapter extension --artifacts-dir artifacts \
|
|
51
|
+
--library "team=~/dev/team-recipes"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Promoting a flow (building your history)
|
|
55
|
+
|
|
56
|
+
After a successful run, keep a flow that proved useful:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
mm-harness flows promote --from recipe.json --flow perps.my_baseline \
|
|
60
|
+
--run artifacts # stamps provenance.lastVerified from the passing run
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Promotion is the contract gate: the flow must have a `description`, `ensure_*`
|
|
64
|
+
flows must declare a `postcondition`, and the stored flow is stamped with
|
|
65
|
+
provenance (origin recipe, promotion date, and `lastVerified` only when backed
|
|
66
|
+
by a passing run's artifacts). The personal library is created on first
|
|
67
|
+
promote.
|
|
68
|
+
|
|
69
|
+
## Sharing with your team
|
|
70
|
+
|
|
71
|
+
Sharing is a plain PR: copy or promote the flow into the team's library repo
|
|
72
|
+
and let the team review it like any other change. Their repo, their rules —
|
|
73
|
+
there is no registration step and no org approval involved.
|
|
74
|
+
|
|
75
|
+
## Trust and drift
|
|
76
|
+
|
|
77
|
+
Library flows rot as the app changes. Three guards, cheapest first:
|
|
78
|
+
|
|
79
|
+
1. **Postconditions** — a stale flow fails its postcondition at run time and
|
|
80
|
+
fails the recipe loudly; promotion nudges every flow toward asserting its
|
|
81
|
+
outcome.
|
|
82
|
+
2. **Freshness warnings** — `flows list` and run-start resolution flag flows
|
|
83
|
+
whose `lastVerified` is older than 30 days.
|
|
84
|
+
3. **Provenance in evidence** — `flowResolution` + `resolved-flows.json` make
|
|
85
|
+
it visible exactly which flow, from which source, produced a proof.
|
|
86
|
+
|
|
87
|
+
## Rules for the canonical library
|
|
88
|
+
|
|
89
|
+
Additions to `library/flows/` are held to the flow-catalog maintenance rules
|
|
90
|
+
(`docs/perps-flow-catalog.md`, Recipe Protocol v1 §8.1): parameterized
|
|
91
|
+
primitives over name multiplication, a real reusable domain concept per flow,
|
|
92
|
+
and a small flow budget. If a flow is team- or task-specific, it belongs in a
|
|
93
|
+
team or personal library — that is what the precedence order is for.
|
|
94
|
+
`scripts/check.mjs` validates every committed catalog against the action
|
|
95
|
+
manifests.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Runtime File Conventions
|
|
2
|
+
|
|
3
|
+
This runner uses a small set of file extensions on purpose. The goal is to keep
|
|
4
|
+
MetaMask-specific logic easy to run from either a source checkout or a published
|
|
5
|
+
package without requiring target app builds to transpile runner code.
|
|
6
|
+
|
|
7
|
+
## Extension rules
|
|
8
|
+
|
|
9
|
+
- `runner/src/**/*.ts` — typed runner core: CLI parsing, manifests, adapter binding,
|
|
10
|
+
runtime decisions, and shared helper logic.
|
|
11
|
+
- `library/actions/**/*.mjs`, `orchestration/**/*.mjs`, and `scripts/**/*.mjs` —
|
|
12
|
+
standalone ESM modules that Node executes directly with no build step. Use
|
|
13
|
+
these for action adapters and small injected/runtime helpers.
|
|
14
|
+
- `*.cjs` — compatibility islands only. Keep these quarantined for helper code
|
|
15
|
+
that intentionally needs CommonJS semantics, such as portable `require()`
|
|
16
|
+
execution from shell scripts or bridge code shared with older runtime contexts.
|
|
17
|
+
- `*.sh` — thin OS/device orchestration wrappers for tools such as `simctl`,
|
|
18
|
+
`adb`, Chrome launch, tmux, and filesystem setup. Do not put recipe graph
|
|
19
|
+
execution or MetaMask domain semantics in shell.
|
|
20
|
+
- Plain source `*.js` is not allowed. With `"type": "module"`, `.js` would be
|
|
21
|
+
ESM, but it is visually ambiguous in this runner. Use `.mjs` for direct Node
|
|
22
|
+
scripts or `.ts` for typed core code.
|
|
23
|
+
|
|
24
|
+
## Design intent
|
|
25
|
+
|
|
26
|
+
The mix is intentional only when the boundary is clear:
|
|
27
|
+
|
|
28
|
+
1. TypeScript owns maintainable product/runner decisions.
|
|
29
|
+
2. ESM scripts own no-build runtime adapters and injected helpers.
|
|
30
|
+
3. CommonJS stays isolated where the runtime context makes ESM brittle.
|
|
31
|
+
4. Shell stays at the edge for host/device commands.
|
|
32
|
+
|
|
33
|
+
If a file crosses those boundaries, move the logic inward: shell should call a
|
|
34
|
+
Node module, standalone `.mjs` should become typed `runner/src/**/*.ts` when it grows
|
|
35
|
+
shared domain logic, and new compatibility needs should be documented before
|
|
36
|
+
adding another `.cjs` file.
|