@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,194 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"title": "MetaMask Perps lifecycle smoke",
|
|
4
|
+
"description": "Reusable Recipe v1 smoke that proves a deterministic Perps prestate, opens a small ETH testnet position, verifies it, closes it, and tears down to a clean state.",
|
|
5
|
+
"validate": {
|
|
6
|
+
"workflow": {
|
|
7
|
+
"entry": "status",
|
|
8
|
+
"nodes": {
|
|
9
|
+
"status": {
|
|
10
|
+
"action": "app.status",
|
|
11
|
+
"intent": "Read runner compatibility status",
|
|
12
|
+
"detail": "Confirm the selected MetaMask adapter is connected before trading.",
|
|
13
|
+
"flow": "setup",
|
|
14
|
+
"next": "fixture"
|
|
15
|
+
},
|
|
16
|
+
"fixture": {
|
|
17
|
+
"action": "metamask.wallet.fixture_status",
|
|
18
|
+
"intent": "Verify wallet fixture availability",
|
|
19
|
+
"detail": "Check the preseeded wallet fixture required for deterministic Perps validation.",
|
|
20
|
+
"flow": "setup",
|
|
21
|
+
"next": "wallet-setup"
|
|
22
|
+
},
|
|
23
|
+
"wallet-setup": {
|
|
24
|
+
"action": "metamask.wallet.setup",
|
|
25
|
+
"intent": "Ensure wallet fixture setup is ready",
|
|
26
|
+
"detail": "Confirm onboarding and fixture state before controlling the app.",
|
|
27
|
+
"flow": "wallet",
|
|
28
|
+
"next": "wallet-unlock"
|
|
29
|
+
},
|
|
30
|
+
"wallet-unlock": {
|
|
31
|
+
"action": "metamask.wallet.ensure_unlocked",
|
|
32
|
+
"intent": "Ensure the wallet is unlocked",
|
|
33
|
+
"detail": "Unlock only if the app is currently locked.",
|
|
34
|
+
"flow": "wallet",
|
|
35
|
+
"next": "select-account"
|
|
36
|
+
},
|
|
37
|
+
"select-account": {
|
|
38
|
+
"action": "metamask.wallet.select_account",
|
|
39
|
+
"address": "0x8dc623e964475d4d669da601fd15ea9125469003",
|
|
40
|
+
"intent": "Select the validation account",
|
|
41
|
+
"detail": "Use the deterministic testnet account shared by mobile and extension.",
|
|
42
|
+
"flow": "wallet",
|
|
43
|
+
"next": "wallet-read-state"
|
|
44
|
+
},
|
|
45
|
+
"wallet-read-state": {
|
|
46
|
+
"action": "metamask.wallet.read_state",
|
|
47
|
+
"intent": "Capture wallet state proof",
|
|
48
|
+
"detail": "Record selected account/network state before the Perps lifecycle.",
|
|
49
|
+
"flow": "wallet",
|
|
50
|
+
"next": "navigate-perps"
|
|
51
|
+
},
|
|
52
|
+
"navigate-perps": {
|
|
53
|
+
"action": "ui.navigate",
|
|
54
|
+
"intent": "Navigate to Perps with raw platform routing",
|
|
55
|
+
"detail": "Mobile consumes route=PerpsMarketListView; extension consumes hash=#/?tab=perps.",
|
|
56
|
+
"flow": "perps setup",
|
|
57
|
+
"next": "navigate-market",
|
|
58
|
+
"route": "PerpsMarketListView",
|
|
59
|
+
"hash": "#/?tab=perps"
|
|
60
|
+
},
|
|
61
|
+
"navigate-market": {
|
|
62
|
+
"action": "ui.navigate",
|
|
63
|
+
"intent": "Open the ETH Perps market with raw platform routing",
|
|
64
|
+
"detail": "Mobile consumes route=params; extension consumes hash=#/perps/market/ETH.",
|
|
65
|
+
"flow": "perps setup",
|
|
66
|
+
"next": "start-state",
|
|
67
|
+
"route": "PerpsMarketDetails",
|
|
68
|
+
"params": {
|
|
69
|
+
"market": {
|
|
70
|
+
"symbol": "ETH"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"hash": "#/perps/market/ETH"
|
|
74
|
+
},
|
|
75
|
+
"start-state": {
|
|
76
|
+
"action": "metamask.perps.start_state",
|
|
77
|
+
"profile": "clean_market_testnet",
|
|
78
|
+
"market": "ETH",
|
|
79
|
+
"positions": {
|
|
80
|
+
"state": "none",
|
|
81
|
+
"mode": "matching"
|
|
82
|
+
},
|
|
83
|
+
"orders": {
|
|
84
|
+
"state": "none",
|
|
85
|
+
"mode": "matching"
|
|
86
|
+
},
|
|
87
|
+
"page": "market",
|
|
88
|
+
"intent": "Prepare clean ETH testnet Perps state",
|
|
89
|
+
"detail": "Close existing ETH testnet positions and orders before the smoke lifecycle starts.",
|
|
90
|
+
"flow": "perps setup",
|
|
91
|
+
"next": "assert-clean-position",
|
|
92
|
+
"tutorial": {
|
|
93
|
+
"completed": true
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"assert-clean-position": {
|
|
97
|
+
"action": "metamask.perps.assert_positions",
|
|
98
|
+
"market": "ETH",
|
|
99
|
+
"state": "none",
|
|
100
|
+
"intent": "Confirm ETH position state is clean",
|
|
101
|
+
"detail": "Assert lifecycle starts with no ETH Perps position.",
|
|
102
|
+
"flow": "perps setup",
|
|
103
|
+
"next": "assert-clean-orders"
|
|
104
|
+
},
|
|
105
|
+
"assert-clean-orders": {
|
|
106
|
+
"action": "metamask.perps.assert_orders",
|
|
107
|
+
"market": "ETH",
|
|
108
|
+
"state": "none",
|
|
109
|
+
"intent": "Confirm ETH order state is clean",
|
|
110
|
+
"detail": "Assert lifecycle starts with no ETH Perps orders.",
|
|
111
|
+
"flow": "perps setup",
|
|
112
|
+
"next": "place-order"
|
|
113
|
+
},
|
|
114
|
+
"place-order": {
|
|
115
|
+
"action": "metamask.perps.place_order",
|
|
116
|
+
"market": "ETH",
|
|
117
|
+
"side": "long",
|
|
118
|
+
"amount": "11",
|
|
119
|
+
"leverage": 3,
|
|
120
|
+
"intent": "Open a small ETH 3x long position",
|
|
121
|
+
"detail": "Place an approximately $11 real testnet market order through the Perps controller.",
|
|
122
|
+
"flow": "perps lifecycle",
|
|
123
|
+
"next": "assert-open"
|
|
124
|
+
},
|
|
125
|
+
"assert-open": {
|
|
126
|
+
"action": "metamask.perps.assert_positions",
|
|
127
|
+
"market": "ETH",
|
|
128
|
+
"state": "open",
|
|
129
|
+
"intent": "Confirm the ETH position opened",
|
|
130
|
+
"detail": "Verify the lifecycle created a real position before cleanup.",
|
|
131
|
+
"flow": "perps lifecycle",
|
|
132
|
+
"next": "read-orders"
|
|
133
|
+
},
|
|
134
|
+
"read-orders": {
|
|
135
|
+
"action": "metamask.perps.read_orders",
|
|
136
|
+
"market": "ETH",
|
|
137
|
+
"intent": "Read ETH orders before cleanup",
|
|
138
|
+
"detail": "Collect order state proof before lifecycle teardown.",
|
|
139
|
+
"flow": "perps lifecycle",
|
|
140
|
+
"next": "close-orders"
|
|
141
|
+
},
|
|
142
|
+
"close-orders": {
|
|
143
|
+
"action": "metamask.perps.close_orders",
|
|
144
|
+
"market": "ETH",
|
|
145
|
+
"intent": "Close ETH orders from the lifecycle",
|
|
146
|
+
"detail": "Cancel any open ETH orders selected by the recipe parameters.",
|
|
147
|
+
"flow": "perps teardown",
|
|
148
|
+
"next": "close-position"
|
|
149
|
+
},
|
|
150
|
+
"close-position": {
|
|
151
|
+
"action": "metamask.perps.close_positions",
|
|
152
|
+
"market": "ETH",
|
|
153
|
+
"intent": "Close the ETH lifecycle position",
|
|
154
|
+
"detail": "Close the position created by this smoke and wait for clean state.",
|
|
155
|
+
"flow": "perps teardown",
|
|
156
|
+
"next": "assert-closed"
|
|
157
|
+
},
|
|
158
|
+
"assert-closed": {
|
|
159
|
+
"action": "metamask.perps.assert_positions",
|
|
160
|
+
"market": "ETH",
|
|
161
|
+
"state": "none",
|
|
162
|
+
"intent": "Confirm ETH position cleanup completed",
|
|
163
|
+
"detail": "Assert no ETH position remains after lifecycle cleanup.",
|
|
164
|
+
"flow": "perps teardown",
|
|
165
|
+
"next": "teardown-state"
|
|
166
|
+
},
|
|
167
|
+
"teardown-state": {
|
|
168
|
+
"action": "metamask.perps.teardown_state",
|
|
169
|
+
"market": "ETH",
|
|
170
|
+
"positions": {
|
|
171
|
+
"state": "none",
|
|
172
|
+
"mode": "matching"
|
|
173
|
+
},
|
|
174
|
+
"orders": {
|
|
175
|
+
"state": "none",
|
|
176
|
+
"mode": "matching"
|
|
177
|
+
},
|
|
178
|
+
"page": "home",
|
|
179
|
+
"intent": "Return Perps to globally clean home state",
|
|
180
|
+
"detail": "Close remaining ETH positions and orders so the lifecycle leaves its selected market clean.",
|
|
181
|
+
"flow": "perps teardown",
|
|
182
|
+
"next": "done"
|
|
183
|
+
},
|
|
184
|
+
"done": {
|
|
185
|
+
"action": "end",
|
|
186
|
+
"status": "pass",
|
|
187
|
+
"intent": "Finish Perps lifecycle smoke",
|
|
188
|
+
"detail": "The recipe opened and closed a real ETH testnet position.",
|
|
189
|
+
"flow": "complete"
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"title": "MetaMask core headless Perps read",
|
|
4
|
+
"description": "Proves the headless `core` adapter instantiates @metamask/perps-controller against a resolved MetaMask/core checkout and reads live HyperLiquid testnet Perps state (positions, open orders, account state) over HTTP — no CDP, bridge, or UI.",
|
|
5
|
+
"validate": {
|
|
6
|
+
"workflow": {
|
|
7
|
+
"entry": "status",
|
|
8
|
+
"nodes": {
|
|
9
|
+
"status": {
|
|
10
|
+
"action": "app.status",
|
|
11
|
+
"next": "read_positions",
|
|
12
|
+
"intent": "Resolve the core checkout and report headless compatibility mode"
|
|
13
|
+
},
|
|
14
|
+
"read_positions": {
|
|
15
|
+
"action": "metamask.perps.read_positions",
|
|
16
|
+
"mode": "all",
|
|
17
|
+
"next": "read_orders",
|
|
18
|
+
"intent": "Read live Perps positions from the headless controller"
|
|
19
|
+
},
|
|
20
|
+
"read_orders": {
|
|
21
|
+
"action": "metamask.perps.read_orders",
|
|
22
|
+
"mode": "all",
|
|
23
|
+
"next": "read_account",
|
|
24
|
+
"intent": "Read live Perps open orders from the headless controller"
|
|
25
|
+
},
|
|
26
|
+
"read_account": {
|
|
27
|
+
"action": "metamask.perps.read_account",
|
|
28
|
+
"next": "done",
|
|
29
|
+
"intent": "Read live Perps account state from the headless controller"
|
|
30
|
+
},
|
|
31
|
+
"done": {
|
|
32
|
+
"action": "end",
|
|
33
|
+
"status": "pass"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"title": "MetaMask Extension v1 runner smoke",
|
|
4
|
+
"description": "Proves the MetaMask Extension runner executes manifest-declared actions and writes a valid artifact package.",
|
|
5
|
+
"validate": {
|
|
6
|
+
"workflow": {
|
|
7
|
+
"entry": "status",
|
|
8
|
+
"nodes": {
|
|
9
|
+
"status": {
|
|
10
|
+
"action": "app.status",
|
|
11
|
+
"next": "fixture",
|
|
12
|
+
"intent": "Perform status for the recipe"
|
|
13
|
+
},
|
|
14
|
+
"fixture": {
|
|
15
|
+
"action": "metamask.wallet.fixture_status",
|
|
16
|
+
"next": "cdp",
|
|
17
|
+
"intent": "Perform fixture for the recipe"
|
|
18
|
+
},
|
|
19
|
+
"cdp": {
|
|
20
|
+
"action": "cdp.target",
|
|
21
|
+
"next": "done",
|
|
22
|
+
"intent": "Perform cdp for the recipe"
|
|
23
|
+
},
|
|
24
|
+
"done": {
|
|
25
|
+
"action": "end",
|
|
26
|
+
"status": "pass"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"title": "MetaMask Mobile v1 runner smoke",
|
|
4
|
+
"description": "Proves the MetaMask Mobile runner executes manifest-declared actions and writes a valid artifact package.",
|
|
5
|
+
"validate": {
|
|
6
|
+
"workflow": {
|
|
7
|
+
"entry": "status",
|
|
8
|
+
"nodes": {
|
|
9
|
+
"status": {
|
|
10
|
+
"action": "app.status",
|
|
11
|
+
"next": "fixture",
|
|
12
|
+
"intent": "Perform status for the recipe"
|
|
13
|
+
},
|
|
14
|
+
"fixture": {
|
|
15
|
+
"action": "metamask.wallet.fixture_status",
|
|
16
|
+
"next": "cdp",
|
|
17
|
+
"intent": "Perform fixture for the recipe"
|
|
18
|
+
},
|
|
19
|
+
"cdp": {
|
|
20
|
+
"action": "cdp.target",
|
|
21
|
+
"next": "done",
|
|
22
|
+
"intent": "Perform cdp for the recipe"
|
|
23
|
+
},
|
|
24
|
+
"done": {
|
|
25
|
+
"action": "end",
|
|
26
|
+
"status": "pass"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"title": "MetaMask core headless Perps trading lifecycle",
|
|
4
|
+
"description": "Proves the headless `core` adapter places and closes a REAL Perps order on HyperLiquid testnet through the full signing path: a default viem signer backs the perps controller's wallet adapter, the active HyperLiquid testnet provider is initialized, and a small BTC long is opened then closed. Leaves the account FLAT. No CDP, bridge, or UI.",
|
|
5
|
+
"validate": {
|
|
6
|
+
"workflow": {
|
|
7
|
+
"entry": "status",
|
|
8
|
+
"nodes": {
|
|
9
|
+
"status": {
|
|
10
|
+
"action": "app.status",
|
|
11
|
+
"next": "start_flat",
|
|
12
|
+
"intent": "Resolve the core checkout and report headless compatibility mode"
|
|
13
|
+
},
|
|
14
|
+
"start_flat": {
|
|
15
|
+
"action": "metamask.perps.start_state",
|
|
16
|
+
"market": "BTC",
|
|
17
|
+
"positions": { "state": "none" },
|
|
18
|
+
"orders": { "state": "none" },
|
|
19
|
+
"network": "testnet",
|
|
20
|
+
"timeout_ms": 45000,
|
|
21
|
+
"next": "place_order",
|
|
22
|
+
"intent": "Converge BTC testnet baseline to flat (no positions, no orders) before the proof window"
|
|
23
|
+
},
|
|
24
|
+
"place_order": {
|
|
25
|
+
"action": "metamask.perps.place_order",
|
|
26
|
+
"market": "BTC",
|
|
27
|
+
"side": "long",
|
|
28
|
+
"notional": "11",
|
|
29
|
+
"leverage": 2,
|
|
30
|
+
"network": "testnet",
|
|
31
|
+
"timeout_ms": 45000,
|
|
32
|
+
"next": "assert_open",
|
|
33
|
+
"intent": "Place a small BTC long market order via the headless controller (real signed order to HL testnet)"
|
|
34
|
+
},
|
|
35
|
+
"assert_open": {
|
|
36
|
+
"action": "metamask.perps.assert_positions",
|
|
37
|
+
"market": "BTC",
|
|
38
|
+
"state": "open",
|
|
39
|
+
"timeout_ms": 30000,
|
|
40
|
+
"next": "close_position",
|
|
41
|
+
"intent": "Assert the BTC position opened"
|
|
42
|
+
},
|
|
43
|
+
"close_position": {
|
|
44
|
+
"action": "metamask.perps.close_positions",
|
|
45
|
+
"market": "BTC",
|
|
46
|
+
"network": "testnet",
|
|
47
|
+
"timeout_ms": 45000,
|
|
48
|
+
"next": "assert_flat",
|
|
49
|
+
"intent": "Close the BTC position via the headless controller (real signed close to HL testnet)"
|
|
50
|
+
},
|
|
51
|
+
"assert_flat": {
|
|
52
|
+
"action": "metamask.perps.assert_positions",
|
|
53
|
+
"market": "BTC",
|
|
54
|
+
"state": "none",
|
|
55
|
+
"timeout_ms": 30000,
|
|
56
|
+
"next": "teardown_flat",
|
|
57
|
+
"intent": "Assert the BTC position closed — account is flat"
|
|
58
|
+
},
|
|
59
|
+
"teardown_flat": {
|
|
60
|
+
"action": "metamask.perps.teardown_state",
|
|
61
|
+
"market": "BTC",
|
|
62
|
+
"positions": { "state": "none" },
|
|
63
|
+
"orders": { "state": "none" },
|
|
64
|
+
"network": "testnet",
|
|
65
|
+
"timeout_ms": 45000,
|
|
66
|
+
"next": "done",
|
|
67
|
+
"intent": "Restore BTC testnet baseline to flat after the proof (leave the shared account clean)"
|
|
68
|
+
},
|
|
69
|
+
"done": {
|
|
70
|
+
"action": "end",
|
|
71
|
+
"status": "pass"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Compatibility overlays (historical-commit replay)
|
|
2
|
+
|
|
3
|
+
NOT dead code. These overlays exist for replay/eval runs against OLD product
|
|
4
|
+
commits — e.g. re-running a historical task on a fixed baseline to validate
|
|
5
|
+
prompt or harness changes. A "zero current references" scan will always come
|
|
6
|
+
up empty here by design: the feature's purpose is non-current checkouts.
|
|
7
|
+
|
|
8
|
+
- Purpose: make historical product checkouts bootable/bridgeable under the
|
|
9
|
+
current local toolchain so Recipe v1 evals can replay against them.
|
|
10
|
+
- When it applies: mobile checkouts predating React Native 0.81 polyfill
|
|
11
|
+
fixes (see mobile/README.md for the per-patch details).
|
|
12
|
+
- How it is applied: MANUALLY (no automatic apply logic in this repo).
|
|
13
|
+
The operator or the `/recipe-harness` skill applies the patch reversibly
|
|
14
|
+
before a historical rebuild (`git apply <patch>` in the product checkout,
|
|
15
|
+
`git apply -R` to remove) and records the overlay path in validation
|
|
16
|
+
evidence. `orchestration/mobile/inject.sh` does NOT apply these.
|
|
17
|
+
|
|
18
|
+
Listed in orchestration/manifest.json (kind: compat-overlay) so the doctor
|
|
19
|
+
verifies the surface and this directory is never flagged as unused again.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Mobile historical compatibility overlays
|
|
2
|
+
|
|
3
|
+
These patch files document temporary source overlays used by Recipe v1 historical
|
|
4
|
+
injection evals when an older MetaMask Mobile checkout cannot boot under the
|
|
5
|
+
current local Xcode/Hermes toolchain.
|
|
6
|
+
|
|
7
|
+
They are intentionally kept in the external runner repository, not Farmslot root
|
|
8
|
+
scripts, so a `/recipe-harness` skill can apply the same reversible overlay before
|
|
9
|
+
a historical rebuild and record the overlay path in validation evidence.
|
|
10
|
+
|
|
11
|
+
- `rn81-message-event-source.patch`: adds a read-only `MessageEvent.prototype.source`
|
|
12
|
+
getter for React Native 0.81 historical checkouts whose bundled polyfill omits
|
|
13
|
+
it while CDP websocket clients expect browser-compatible `MessageEvent` shape.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
compat-overlay: rn81-message-event-source (historical-checkout replay support)
|
|
2
|
+
|
|
3
|
+
What: patches metamask-mobile shim.js to add a read-only
|
|
4
|
+
MessageEvent.prototype.source getter.
|
|
5
|
+
Why: the harness CDP bridge expects browser-compatible MessageEvent shape;
|
|
6
|
+
pre-RN-0.81 checkouts ship a polyfill that omits .source, so the bridge
|
|
7
|
+
cannot attach when replaying tasks on those historical commits.
|
|
8
|
+
When: only when replaying/evaluating against mobile checkouts older than the
|
|
9
|
+
RN 0.81 upgrade (pre-RN-0.81 checkouts). Never needed on current main.
|
|
10
|
+
How: applied MANUALLY in the historical product checkout —
|
|
11
|
+
git apply <this file> (and `git apply -R` to remove)
|
|
12
|
+
No automatic apply logic exists in this repo. See ../README.md.
|
|
13
|
+
|
|
14
|
+
diff --git a/shim.js b/shim.js
|
|
15
|
+
--- a/shim.js
|
|
16
|
+
+++ b/shim.js
|
|
17
|
+
@@
|
|
18
|
+
if (typeof global.MessageEvent === 'undefined') {
|
|
19
|
+
global.MessageEvent =
|
|
20
|
+
require('react-native/src/private/webapis/html/events/MessageEvent').default;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
+// Historical runner compatibility: React Native 0.81's MessageEvent polyfill
|
|
24
|
+
+// can omit the browser `source` getter expected by CDP websocket clients under
|
|
25
|
+
+// newer Xcode/Hermes toolchains. Keep the getter read-only and null, matching
|
|
26
|
+
+// browser MessageEvent semantics for non-window messages.
|
|
27
|
+
+if (
|
|
28
|
+
+ global.MessageEvent?.prototype &&
|
|
29
|
+
+ !Object.getOwnPropertyDescriptor(global.MessageEvent.prototype, 'source')
|
|
30
|
+
+) {
|
|
31
|
+
+ Object.defineProperty(global.MessageEvent.prototype, 'source', {
|
|
32
|
+
+ configurable: true,
|
|
33
|
+
+ enumerable: true,
|
|
34
|
+
+ get() {
|
|
35
|
+
+ return null;
|
|
36
|
+
+ },
|
|
37
|
+
+ });
|
|
38
|
+
+}
|
|
39
|
+
+
|
|
40
|
+
class AbortError extends Error {
|
|
41
|
+
constructor(message) {
|
|
42
|
+
super(message);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# cleanup.sh — remove the headless `core` adapter overlay.
|
|
3
|
+
#
|
|
4
|
+
# Inputs: --target <metamask-core> (default $PWD); env RECIPE_HARNESS_ROOT.
|
|
5
|
+
# Outputs: removes <harness>/core. Exit 0 — cleaned (idempotent); 2 — bad args.
|
|
6
|
+
# Never touches: product files (core install patches nothing).
|
|
7
|
+
#
|
|
8
|
+
# Core injects nothing into the product checkout, so cleanup only removes the
|
|
9
|
+
# ignored overlay directory temp/recipe/harness/core. There are no backups to
|
|
10
|
+
# restore and no patched product files. Idempotent: a missing overlay is a
|
|
11
|
+
# success, not an error.
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
TARGET="$PWD"
|
|
15
|
+
while [ "$#" -gt 0 ]; do
|
|
16
|
+
case "$1" in
|
|
17
|
+
--target) TARGET="$2"; shift 2 ;;
|
|
18
|
+
-h|--help) echo "Usage: cleanup.sh (core) [--target <metamask-core>]"; exit 0 ;;
|
|
19
|
+
*) echo "Unknown arg: $1" >&2; exit 2 ;;
|
|
20
|
+
esac
|
|
21
|
+
done
|
|
22
|
+
|
|
23
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
24
|
+
TARGET="$(cd "$TARGET" && pwd)"
|
|
25
|
+
# shellcheck disable=SC1091
|
|
26
|
+
for _hp in "$SCRIPT_DIR/../lib/harness-path.sh"; do
|
|
27
|
+
[ -f "$_hp" ] && { . "$_hp"; break; }
|
|
28
|
+
done
|
|
29
|
+
unset _hp
|
|
30
|
+
if ! command -v harness_root >/dev/null 2>&1; then
|
|
31
|
+
echo "mm-harness: shared lib orchestration/lib/harness-path.sh not found; reinstall the runner." >&2
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
HARNESS_DIR="$(harness_dir "$TARGET" core)"
|
|
35
|
+
|
|
36
|
+
rm -rf "$HARNESS_DIR"
|
|
37
|
+
echo "Cleaned core recipe harness from $TARGET"
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# inject.sh — headless `core` adapter install.
|
|
3
|
+
#
|
|
4
|
+
# Inputs: --target <metamask-core> (default $PWD); env RECIPE_HARNESS_ROOT,
|
|
5
|
+
# METAMASK_RUNNER_PROTOCOL_ROOT > FARMSLOT_ROOT > <runner>/.farmslot-root.
|
|
6
|
+
# Outputs: <harness>/core/{manifest.json,action-manifest.json,runner/}.
|
|
7
|
+
# Exit 0 — installed; 1 — symlink refusal/install failure; 2 — bad args.
|
|
8
|
+
# Never touches: product checkout source (overlay metadata only).
|
|
9
|
+
#
|
|
10
|
+
# Core is a headless adapter: it instantiates @metamask/perps-controller against
|
|
11
|
+
# a resolved MetaMask/core checkout and reads/writes HyperLiquid testnet over
|
|
12
|
+
# HTTP. There is no app, CDP target, bridge, or UI. Unlike the mobile/extension
|
|
13
|
+
# installs this writes NOTHING into the product checkout source: it only creates
|
|
14
|
+
# the ignored harness overlay under temp/recipe/harness/core with a delegate
|
|
15
|
+
# wrapper, the action manifests, recipe snapshots, and install metadata.
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
TARGET="$PWD"
|
|
19
|
+
while [ "$#" -gt 0 ]; do
|
|
20
|
+
case "$1" in
|
|
21
|
+
--target) TARGET="$2"; shift 2 ;;
|
|
22
|
+
-h|--help) echo "Usage: inject.sh (core) [--target <metamask-core>]"; exit 0 ;;
|
|
23
|
+
*) echo "Unknown arg: $1" >&2; exit 2 ;;
|
|
24
|
+
esac
|
|
25
|
+
done
|
|
26
|
+
|
|
27
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
28
|
+
RUNNER_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd -P)"
|
|
29
|
+
# shellcheck disable=SC1091
|
|
30
|
+
for _hp in "$SCRIPT_DIR/../lib/harness-path.sh"; do
|
|
31
|
+
[ -f "$_hp" ] && { . "$_hp"; break; }
|
|
32
|
+
done
|
|
33
|
+
unset _hp
|
|
34
|
+
if ! command -v harness_root >/dev/null 2>&1; then
|
|
35
|
+
echo "mm-harness: shared lib orchestration/lib/harness-path.sh not found; reinstall the runner." >&2
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
TARGET="$(cd "$TARGET" && pwd)"
|
|
39
|
+
METAMASK_RUNNER_DIR="$RUNNER_DIR"
|
|
40
|
+
METAMASK_RUNNER_SOURCE_KIND="runner-self"
|
|
41
|
+
METAMASK_RUNNER_REVISION="$(git -C "$RUNNER_DIR" rev-parse HEAD 2>/dev/null || echo unknown)"
|
|
42
|
+
METAMASK_RUNNER_PROTOCOL_ROOT="${METAMASK_RUNNER_PROTOCOL_ROOT:-${METAMASK_RUNNER_FARMSLOT_ROOT:-${FARMSLOT_ROOT:-}}}"
|
|
43
|
+
if [ -z "$METAMASK_RUNNER_PROTOCOL_ROOT" ] && [ -f "$RUNNER_DIR/.farmslot-root" ]; then
|
|
44
|
+
METAMASK_RUNNER_PROTOCOL_ROOT="$(cat "$RUNNER_DIR/.farmslot-root")"
|
|
45
|
+
fi
|
|
46
|
+
export METAMASK_RUNNER_DIR METAMASK_RUNNER_SOURCE_KIND METAMASK_RUNNER_REVISION METAMASK_RUNNER_PROTOCOL_ROOT
|
|
47
|
+
HARNESS_ROOT="$(harness_root)"
|
|
48
|
+
HARNESS_REL="$HARNESS_ROOT/core"
|
|
49
|
+
HARNESS_DIR="$(harness_dir "$TARGET" core)"
|
|
50
|
+
|
|
51
|
+
refuse_symlink_destination() {
|
|
52
|
+
local rel="$1"
|
|
53
|
+
local path_so_far="$TARGET"
|
|
54
|
+
IFS='/' read -r -a parts <<< "$rel"
|
|
55
|
+
for part in "${parts[@]}"; do
|
|
56
|
+
[ -n "$part" ] || continue
|
|
57
|
+
path_so_far="$path_so_far/$part"
|
|
58
|
+
if [ -L "$path_so_far" ]; then
|
|
59
|
+
echo "Refusing core recipe harness install: $rel contains symlink component $path_so_far." >&2
|
|
60
|
+
return 1
|
|
61
|
+
fi
|
|
62
|
+
done
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
install_v1_runner_assets() {
|
|
66
|
+
# refuse_symlink_destination walks every path component, so the deepest paths
|
|
67
|
+
# also guard their parents ($HARNESS_REL covers the root segments).
|
|
68
|
+
refuse_symlink_destination "$HARNESS_REL"
|
|
69
|
+
refuse_symlink_destination "$HARNESS_REL/runner"
|
|
70
|
+
refuse_symlink_destination "$HARNESS_REL/action-manifest.json"
|
|
71
|
+
mkdir -p "$HARNESS_DIR"
|
|
72
|
+
rm -rf "$HARNESS_DIR/runner"
|
|
73
|
+
mkdir -p "$HARNESS_DIR/runner/bin" "$HARNESS_DIR/runner/manifests" "$HARNESS_DIR/runner/recipes"
|
|
74
|
+
|
|
75
|
+
# Install a harness-owned delegate that execs the reviewed external runner
|
|
76
|
+
# source recorded in manifest.json. The delegate keeps the overlay lightweight
|
|
77
|
+
# and never owns the runtime itself. Core is headless: no app, no .js.env, no
|
|
78
|
+
# simulator detection — the delegate only forwards FARMSLOT_ROOT (when set) and
|
|
79
|
+
# execs the real runner. Emit shell-safe lines: %q-quote the interpolated paths
|
|
80
|
+
# so a protocol/runner path containing a space — or $()/backtick/quote — cannot
|
|
81
|
+
# break the generated wrapper or inject at runtime.
|
|
82
|
+
local runner_protocol_root_q runner_exec_q
|
|
83
|
+
runner_protocol_root_q="$(printf '%q' "$METAMASK_RUNNER_PROTOCOL_ROOT")"
|
|
84
|
+
runner_exec_q="$(printf '%q' "$METAMASK_RUNNER_DIR/orchestration/porcelain/metamask-recipe")"
|
|
85
|
+
{
|
|
86
|
+
printf '%s\n' '#!/usr/bin/env bash'
|
|
87
|
+
printf '%s\n' 'set -euo pipefail'
|
|
88
|
+
if [ -n "$METAMASK_RUNNER_PROTOCOL_ROOT" ]; then
|
|
89
|
+
printf 'export FARMSLOT_ROOT=${FARMSLOT_ROOT:-%s}\n' "$runner_protocol_root_q"
|
|
90
|
+
fi
|
|
91
|
+
printf 'exec %s "$@"\n' "$runner_exec_q"
|
|
92
|
+
} > "$HARNESS_DIR/runner/bin/metamask-recipe"
|
|
93
|
+
chmod +x "$HARNESS_DIR/runner/bin/metamask-recipe"
|
|
94
|
+
if [ -n "$METAMASK_RUNNER_PROTOCOL_ROOT" ]; then
|
|
95
|
+
printf '%s\n' "$METAMASK_RUNNER_PROTOCOL_ROOT" > "$HARNESS_DIR/runner/.farmslot-root"
|
|
96
|
+
fi
|
|
97
|
+
printf '%s\n' "$METAMASK_RUNNER_DIR" > "$HARNESS_DIR/runner/.runner-source"
|
|
98
|
+
# resolve-runner-source.sh requires mobile + extension manifests to consider a
|
|
99
|
+
# runner valid, so the installed delegate must carry them alongside core's.
|
|
100
|
+
cp "$METAMASK_RUNNER_DIR/library/manifests/core.action-manifest.json" "$HARNESS_DIR/action-manifest.json"
|
|
101
|
+
cp "$METAMASK_RUNNER_DIR/library/manifests/core.action-manifest.json" "$HARNESS_DIR/runner/manifests/core.action-manifest.json"
|
|
102
|
+
cp "$METAMASK_RUNNER_DIR/library/manifests/mobile.action-manifest.json" "$HARNESS_DIR/runner/manifests/mobile.action-manifest.json"
|
|
103
|
+
cp "$METAMASK_RUNNER_DIR/library/manifests/extension.action-manifest.json" "$HARNESS_DIR/runner/manifests/extension.action-manifest.json"
|
|
104
|
+
if [ -d "$METAMASK_RUNNER_DIR/library/recipes" ]; then
|
|
105
|
+
rsync -a --delete "$METAMASK_RUNNER_DIR/library/recipes/" "$HARNESS_DIR/runner/recipes/"
|
|
106
|
+
fi
|
|
107
|
+
# Canonical recipe-library snapshot: flows/ + library.json so the installed
|
|
108
|
+
# harness mirrors the runner's library layout.
|
|
109
|
+
if [ -d "$METAMASK_RUNNER_DIR/library/flows" ]; then
|
|
110
|
+
mkdir -p "$HARNESS_DIR/runner/flows"
|
|
111
|
+
rsync -a --delete "$METAMASK_RUNNER_DIR/library/flows/" "$HARNESS_DIR/runner/flows/"
|
|
112
|
+
fi
|
|
113
|
+
if [ -f "$METAMASK_RUNNER_DIR/library/library.json" ]; then
|
|
114
|
+
cp "$METAMASK_RUNNER_DIR/library/library.json" "$HARNESS_DIR/runner/library.json"
|
|
115
|
+
fi
|
|
116
|
+
if [ ! -x "$HARNESS_DIR/runner/bin/metamask-recipe" ]; then
|
|
117
|
+
echo "Refusing core recipe harness install: failed to make runner executable." >&2
|
|
118
|
+
return 1
|
|
119
|
+
fi
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
install_v1_runner_assets
|
|
123
|
+
|
|
124
|
+
ENSURE_DEPS="$SCRIPT_DIR/../lib/ensure-runner-deps.sh"
|
|
125
|
+
if [ -f "$ENSURE_DEPS" ]; then
|
|
126
|
+
bash "$ENSURE_DEPS" "$RUNNER_DIR"
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
SOURCE_REV="$(git -C "$RUNNER_DIR" rev-parse HEAD 2>/dev/null || echo unknown)"
|
|
130
|
+
CLEANUP_COMMAND="RECIPE_HARNESS_ROOT=$HARNESS_ROOT $(printf '%q' "$SCRIPT_DIR/cleanup.sh") --target $(printf '%q' "$TARGET")"
|
|
131
|
+
node -e '
|
|
132
|
+
const fs = require("fs");
|
|
133
|
+
const [runnerDir, runnerRevision, runnerSourceKind, target, manifestPath, harnessRel, cleanupCommand] = process.argv.slice(1);
|
|
134
|
+
const m = {
|
|
135
|
+
adapter: "core",
|
|
136
|
+
installedAt: new Date().toISOString(),
|
|
137
|
+
source: {
|
|
138
|
+
runnerDir,
|
|
139
|
+
runnerRevision,
|
|
140
|
+
runnerSourceKind,
|
|
141
|
+
},
|
|
142
|
+
target,
|
|
143
|
+
protocolVersion: "v1",
|
|
144
|
+
actionManifestPath: harnessRel + "/action-manifest.json",
|
|
145
|
+
runnerEntrypoint: harnessRel + "/runner/bin/metamask-recipe",
|
|
146
|
+
runtimeHelpers: {},
|
|
147
|
+
installedPaths: [harnessRel + "/runner"],
|
|
148
|
+
patchedFiles: [],
|
|
149
|
+
cleanupCommand,
|
|
150
|
+
};
|
|
151
|
+
fs.writeFileSync(manifestPath, JSON.stringify(m, null, 2) + "\n");
|
|
152
|
+
' "$METAMASK_RUNNER_DIR" "$METAMASK_RUNNER_REVISION" "$METAMASK_RUNNER_SOURCE_KIND" "$TARGET" "$HARNESS_DIR/manifest.json" "$HARNESS_REL" "$CLEANUP_COMMAND"
|
|
153
|
+
|
|
154
|
+
echo "Installed core recipe harness: $HARNESS_DIR/manifest.json"
|