@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.
Files changed (158) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/README.md +140 -0
  3. package/bin/mm-harness +99 -0
  4. package/docs/CHEATSHEET.md +61 -0
  5. package/docs/CLI-SPEC.md +915 -0
  6. package/docs/MENTAL-MODEL.md +295 -0
  7. package/docs/architecture.md +367 -0
  8. package/docs/extension-runtime-commands.md +60 -0
  9. package/docs/harness-cli.md +43 -0
  10. package/docs/live-adapter-contract.md +188 -0
  11. package/docs/package-boundaries.md +47 -0
  12. package/docs/perps-flow-catalog.md +235 -0
  13. package/docs/recipe-libraries.md +95 -0
  14. package/docs/runtime-file-conventions.md +36 -0
  15. package/library/actions/core/perps/_controller.mjs +727 -0
  16. package/library/actions/core/perps/assert_orders.mjs +53 -0
  17. package/library/actions/core/perps/assert_positions.mjs +52 -0
  18. package/library/actions/core/perps/close_orders.mjs +97 -0
  19. package/library/actions/core/perps/close_positions.mjs +118 -0
  20. package/library/actions/core/perps/ensure_orders.mjs +40 -0
  21. package/library/actions/core/perps/ensure_positions.mjs +37 -0
  22. package/library/actions/core/perps/place_order.mjs +201 -0
  23. package/library/actions/core/perps/read_account.mjs +30 -0
  24. package/library/actions/core/perps/read_orders.mjs +27 -0
  25. package/library/actions/core/perps/read_positions.mjs +27 -0
  26. package/library/actions/core/perps/start_state.mjs +92 -0
  27. package/library/actions/core/perps/teardown_state.mjs +86 -0
  28. package/library/actions/extension/perps/assert_orders.mjs +11 -0
  29. package/library/actions/extension/perps/assert_positions.mjs +11 -0
  30. package/library/actions/extension/perps/close_orders.mjs +8 -0
  31. package/library/actions/extension/perps/close_positions.mjs +8 -0
  32. package/library/actions/extension/perps/ensure_orders.mjs +4 -0
  33. package/library/actions/extension/perps/ensure_positions.mjs +4 -0
  34. package/library/actions/extension/perps/perps.mjs +730 -0
  35. package/library/actions/extension/perps/place_order.mjs +7 -0
  36. package/library/actions/extension/perps/read_orders.mjs +4 -0
  37. package/library/actions/extension/perps/read_positions.mjs +3 -0
  38. package/library/actions/extension/platform/cdp.mjs +541 -0
  39. package/library/actions/extension/ui/navigate.mjs +44 -0
  40. package/library/actions/extension/wallet/ensure_unlocked.mjs +36 -0
  41. package/library/actions/extension/wallet/read_state.mjs +27 -0
  42. package/library/actions/extension/wallet/select_account.mjs +48 -0
  43. package/library/actions/extension/wallet/setup.mjs +35 -0
  44. package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +185 -0
  45. package/library/actions/mobile/app-overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +1662 -0
  46. package/library/actions/mobile/bridge-runtime/cdp-bridge.cjs +686 -0
  47. package/library/actions/mobile/bridge-runtime/lib/cdp-eval.cjs +110 -0
  48. package/library/actions/mobile/bridge-runtime/lib/config.cjs +39 -0
  49. package/library/actions/mobile/bridge-runtime/lib/issue-capture.cjs +446 -0
  50. package/library/actions/mobile/bridge-runtime/lib/target-discovery.cjs +204 -0
  51. package/library/actions/mobile/bridge-runtime/lib/ws-client.cjs +108 -0
  52. package/library/actions/mobile/bridge-runtime/setup-wallet.sh +442 -0
  53. package/library/actions/mobile/perps/assert_orders.mjs +11 -0
  54. package/library/actions/mobile/perps/assert_positions.mjs +11 -0
  55. package/library/actions/mobile/perps/close_orders.mjs +8 -0
  56. package/library/actions/mobile/perps/close_positions.mjs +8 -0
  57. package/library/actions/mobile/perps/ensure_orders.mjs +4 -0
  58. package/library/actions/mobile/perps/ensure_positions.mjs +4 -0
  59. package/library/actions/mobile/perps/perps.mjs +709 -0
  60. package/library/actions/mobile/perps/place_order.mjs +7 -0
  61. package/library/actions/mobile/perps/read_orders.mjs +4 -0
  62. package/library/actions/mobile/perps/read_positions.mjs +3 -0
  63. package/library/actions/mobile/platform/bridge.mjs +283 -0
  64. package/library/actions/mobile/ui/navigate.mjs +38 -0
  65. package/library/actions/mobile/wallet/ensure_unlocked.mjs +107 -0
  66. package/library/actions/mobile/wallet/home.mjs +35 -0
  67. package/library/actions/mobile/wallet/read_state.mjs +40 -0
  68. package/library/actions/mobile/wallet/select_account.mjs +48 -0
  69. package/library/actions/mobile/wallet/setup.mjs +220 -0
  70. package/library/flows/perps.flows.json +64 -0
  71. package/library/library.json +7 -0
  72. package/library/manifests/core.action-manifest.json +1282 -0
  73. package/library/manifests/extension.action-manifest.json +1749 -0
  74. package/library/manifests/mobile.action-manifest.json +1753 -0
  75. package/library/recipes/action-validation.extension.recipe.json +417 -0
  76. package/library/recipes/action-validation.mobile.recipe.json +422 -0
  77. package/library/recipes/order-lifecycle.core.recipe.json +78 -0
  78. package/library/recipes/perps-lifecycle.recipe.json +194 -0
  79. package/library/recipes/read-markets.core.recipe.json +38 -0
  80. package/library/recipes/smoke.extension.recipe.json +31 -0
  81. package/library/recipes/smoke.mobile.recipe.json +31 -0
  82. package/library/recipes/trading-lifecycle.core.recipe.json +76 -0
  83. package/orchestration/compat-overlays/README.md +19 -0
  84. package/orchestration/compat-overlays/mobile/README.md +13 -0
  85. package/orchestration/compat-overlays/mobile/rn81-message-event-source.patch +42 -0
  86. package/orchestration/core/cleanup.sh +37 -0
  87. package/orchestration/core/inject.sh +154 -0
  88. package/orchestration/doctor.mjs +72 -0
  89. package/orchestration/extension/cleanup.mjs +60 -0
  90. package/orchestration/extension/console-tail.mjs +228 -0
  91. package/orchestration/extension/ensure-browser.sh +416 -0
  92. package/orchestration/extension/ensure-ready.ts +185 -0
  93. package/orchestration/extension/extension-id.ts +107 -0
  94. package/orchestration/extension/inject.mjs +266 -0
  95. package/orchestration/extension/launch-browser.cjs +216 -0
  96. package/orchestration/extension/launch.sh +175 -0
  97. package/orchestration/extension/live.sh +320 -0
  98. package/orchestration/extension/pin-remote-flags.cjs +45 -0
  99. package/orchestration/extension/readiness.mjs +414 -0
  100. package/orchestration/extension/refresh-build.sh +190 -0
  101. package/orchestration/extension/runtime-decision.ts +445 -0
  102. package/orchestration/extension/runtime.ts +407 -0
  103. package/orchestration/extension/seed-fixture.sh +177 -0
  104. package/orchestration/extension/sidepanel-toggle.sh +291 -0
  105. package/orchestration/extension/snapshot-dist.sh +84 -0
  106. package/orchestration/extension/start-watch.sh +339 -0
  107. package/orchestration/extension/wallet-fixture-state.cjs +1086 -0
  108. package/orchestration/lib/activate-repo-node.sh +144 -0
  109. package/orchestration/lib/cli-color.mjs +84 -0
  110. package/orchestration/lib/cli-commands.mjs +243 -0
  111. package/orchestration/lib/cli-home.mjs +354 -0
  112. package/orchestration/lib/cli-ux.sh +252 -0
  113. package/orchestration/lib/cli-version.mjs +123 -0
  114. package/orchestration/lib/ensure-runner-deps.sh +56 -0
  115. package/orchestration/lib/harness-path.sh +55 -0
  116. package/orchestration/lib/hash-helpers.sh +44 -0
  117. package/orchestration/lib/json-field.sh +23 -0
  118. package/orchestration/lib/log-tui.mjs +304 -0
  119. package/orchestration/lib/open-debug.mjs +317 -0
  120. package/orchestration/lib/path-defaults.json +4 -0
  121. package/orchestration/lib/progress.mjs +107 -0
  122. package/orchestration/lib/recipe-paths.mjs +26 -0
  123. package/orchestration/lib/resolve-farmslot-ports.sh +144 -0
  124. package/orchestration/manifest.json +358 -0
  125. package/orchestration/mobile/cleanup.sh +192 -0
  126. package/orchestration/mobile/deps-markers.ts +21 -0
  127. package/orchestration/mobile/inject.sh +681 -0
  128. package/orchestration/mobile/launch.sh +137 -0
  129. package/orchestration/mobile/live.sh +125 -0
  130. package/orchestration/mobile/runtime-decision.ts +292 -0
  131. package/orchestration/porcelain/metamask-recipe +99 -0
  132. package/orchestration/porcelain/mm-recipe +1591 -0
  133. package/orchestration/porcelain/mme-recipe +1181 -0
  134. package/package.json +59 -0
  135. package/runner/extension/verify.sh +511 -0
  136. package/runner/mobile/verify.sh +501 -0
  137. package/runner/src/adapters.ts +601 -0
  138. package/runner/src/cli.ts +1820 -0
  139. package/runner/src/commands/debug.ts +44 -0
  140. package/runner/src/commands/fixtures.ts +99 -0
  141. package/runner/src/commands/launch.ts +397 -0
  142. package/runner/src/commands/logs.ts +60 -0
  143. package/runner/src/commands/shared.ts +138 -0
  144. package/runner/src/completions-cache.ts +86 -0
  145. package/runner/src/doctor.ts +203 -0
  146. package/runner/src/harness.ts +516 -0
  147. package/runner/src/heal-bounds.ts +179 -0
  148. package/runner/src/index.ts +6 -0
  149. package/runner/src/live-adapter-contract.ts +274 -0
  150. package/runner/src/manifest.ts +47 -0
  151. package/runner/src/mm-harness-cli.ts +488 -0
  152. package/runner/src/paths.ts +198 -0
  153. package/runner/src/recording-target.ts +147 -0
  154. package/runner/src/run-recording.ts +329 -0
  155. package/runner/src/runner.ts +108 -0
  156. package/runner/src/types.ts +57 -0
  157. package/scripts/completions.sh +125 -0
  158. package/scripts/install-completions.sh +62 -0
@@ -0,0 +1,358 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "description": "Orchestration feature surface: one entry per feature script. orchestration/doctor.mjs verifies every entry point exists, answers --help with exit 0, and that no orchestration script is missing from this manifest.",
4
+ "features": [
5
+ {
6
+ "id": "mobile/launch",
7
+ "entry": "orchestration/mobile/launch.sh",
8
+ "kind": "bash",
9
+ "purpose": "Mobile instance identity intake (port/simulator/adb/runtime-dir tuple) + prepare/preflight launch.",
10
+ "inputs": "--target --platform --preflight-mode --port|--watcher-port|--cdp-port --simulator --adb-serial --runtime-dir --wallet-setup/--no-wallet-setup --wallet-fixture --artifacts-dir; env WATCHER_PORT>METRO_PORT>CDP_PORT, IOS_SIMULATOR>SIM_UDID, ADB_SERIAL>ANDROID_SERIAL, RECIPE_RUNTIME_DIR, RECIPE_HARNESS_MOBILE_PREFLIGHT_MODE",
11
+ "outputs": "<artifacts>/summary.json, runtime-status.json, logs/prepare.log; exit 0/1/2"
12
+ },
13
+ {
14
+ "id": "mobile/live",
15
+ "entry": "orchestration/mobile/live.sh",
16
+ "kind": "bash",
17
+ "purpose": "Launch-then-verify chaining for one mobile slot run (verify gets --no-auto-start).",
18
+ "inputs": "--target --platform --preflight-mode --artifacts-dir --wallet-setup/--no-wallet-setup --wallet-fixture",
19
+ "outputs": "<artifacts>/summary.json + launch/ + verify/; exit 0/1/2"
20
+ },
21
+ {
22
+ "id": "mobile/inject",
23
+ "entry": "orchestration/mobile/inject.sh",
24
+ "kind": "bash",
25
+ "purpose": "Install the mobile harness overlay (delegate + snapshots; full mode adds the app bridge with backups).",
26
+ "inputs": "--target --allow-dirty-harness-paths --force-overlay --no-git-exclude; env RECIPE_HARNESS_ROOT, METAMASK_RUNNER_PROTOCOL_ROOT>FARMSLOT_ROOT",
27
+ "outputs": "<harness>/manifest.json + runner/ + scripts/ + backup store; exit 0/1/2"
28
+ },
29
+ {
30
+ "id": "mobile/cleanup",
31
+ "entry": "orchestration/mobile/cleanup.sh",
32
+ "kind": "bash",
33
+ "purpose": "Remove the mobile overlay; restore backed-up product files; remove recorded git excludes.",
34
+ "inputs": "--target --allow-managed-changes; env RECIPE_HARNESS_ROOT",
35
+ "outputs": "removes <harness>/ + backups; exit 0/1/2"
36
+ },
37
+ {
38
+ "id": "extension/launch",
39
+ "entry": "orchestration/extension/launch.sh",
40
+ "kind": "bash",
41
+ "purpose": "Run the caller-supplied prepare command for one slot, then confirm app-control readiness.",
42
+ "inputs": "--target --cdp-port --prepare-cmd --artifacts-dir; env RECIPE_HARNESS_EXTENSION_LAUNCH_CMD",
43
+ "outputs": "<artifacts>/summary.json, logs/{launch.log,extension-readiness.json}; exit 0/1/2"
44
+ },
45
+ {
46
+ "id": "extension/live",
47
+ "entry": "orchestration/extension/live.sh",
48
+ "kind": "bash",
49
+ "purpose": "Sequencer: builds the prepare command from the named feature scripts, then launch + verify.",
50
+ "inputs": "--target --cdp-port --launch-existing-dist|--start-watch|--prepare-cmd --dist-dir --chrome-user-data-dir --out --artifacts-dir; env RECIPE_HARNESS_CHROME_BIN, RECIPE_WALLET_FIXTURE, RECIPE_HARNESS_LIVE_KEEP",
51
+ "outputs": "<artifacts>/summary.json + launch/ + verify/ + logs/fixture-source.json; exit 0/1/2"
52
+ },
53
+ {
54
+ "id": "extension/start-watch",
55
+ "entry": "orchestration/extension/start-watch.sh",
56
+ "kind": "bash",
57
+ "purpose": "Harness-owned webpack watcher: cache clear, dual-writer refusal, compile-marker wait, baseline record.",
58
+ "inputs": "--target --runtime-dir --runner-bin --summary",
59
+ "outputs": "<runtime-dir>/recipe-harness-webpack.{pid,log}; optional summary; exit 0/1/2"
60
+ },
61
+ {
62
+ "id": "extension/console-tail",
63
+ "entry": "orchestration/extension/console-tail.mjs",
64
+ "kind": "node",
65
+ "purpose": "Live CDP stream of the running extension console (MV3 service worker + UI pages), re-attaching across service-worker churn; hosts the console tmux tab.",
66
+ "inputs": "--cdp-port [--log <file>]",
67
+ "outputs": "console lines on stdout, optional mirror to --log; exit 0/1/2"
68
+ },
69
+ {
70
+ "id": "extension/snapshot-dist",
71
+ "entry": "orchestration/extension/snapshot-dist.sh",
72
+ "kind": "bash",
73
+ "purpose": "Runtime-dist snapshot (rsync, excludes _metadata) with from-git-id freshness guard.",
74
+ "inputs": "--dist --runtime-dist --wait-iterations --summary",
75
+ "outputs": "<runtime-dist>/ snapshot; optional summary; exit 0/1/2"
76
+ },
77
+ {
78
+ "id": "extension/seed-fixture",
79
+ "entry": "orchestration/extension/seed-fixture.sh",
80
+ "kind": "bash",
81
+ "purpose": "Wallet fixture resolution chain + generate/prefill (pre-launch) and seed-cdp (post-launch) phases.",
82
+ "inputs": "resolve|prefill|seed-cdp; --target --cdp-port --fixture --state --profile --extension-dir --extension-id-file --out --source-out --fixture-script --summary; env RECIPE_WALLET_FIXTURE",
83
+ "outputs": "fixture path on stdout (resolve), provenance/state/parity JSON files; exit 0/1/2"
84
+ },
85
+ {
86
+ "id": "extension/launch-browser",
87
+ "entry": "orchestration/extension/launch-browser.cjs",
88
+ "kind": "node",
89
+ "purpose": "Low-level spawn primitive: detached Chrome with isolated profile, CDP on 127.0.0.1, unpacked dist.",
90
+ "inputs": "--cdp-port --chrome-bin --profile --extension-dir --chrome-log --chrome-pid",
91
+ "outputs": "pid file + append-log; exit 0 / non-zero"
92
+ },
93
+ {
94
+ "id": "extension/refresh-build",
95
+ "entry": "orchestration/extension/refresh-build.sh",
96
+ "kind": "bash",
97
+ "purpose": "One-shot rebuild for a frozen slot: yarn start, wait for entry points, kill watcher (fresh AND frozen).",
98
+ "inputs": "--repo --watcher-port --timeout --clean-timeout",
99
+ "outputs": "refreshed dist/chrome; exit 0/1/2"
100
+ },
101
+ {
102
+ "id": "extension/ensure-browser",
103
+ "entry": "orchestration/extension/ensure-browser.sh",
104
+ "kind": "bash",
105
+ "purpose": "Ensure the slot's Chromium is running against the existing dist/profile/port (kills + relaunches).",
106
+ "inputs": "--slot-id --repo --cdp-port --runtime-dir --watcher-port; env CHROME_USER_DATA_DIR, RECIPE_HARNESS_ROOT",
107
+ "outputs": "<runtime-dir>/{browser.pid,chromium.pid,extension.id}; exit 0/1"
108
+ },
109
+ {
110
+ "id": "extension/inject",
111
+ "entry": "orchestration/extension/inject.mjs",
112
+ "kind": "node",
113
+ "purpose": "Install the extension harness overlay (delegate, manifests, recipes, helper scripts).",
114
+ "inputs": "--target --no-git-exclude; env RECIPE_HARNESS_ROOT, METAMASK_RUNNER_DIR, METAMASK_RUNNER_PROTOCOL_ROOT>FARMSLOT_ROOT",
115
+ "outputs": "<harness>/{manifest.json,action-manifest.json,runner/,scripts/}; exit 0/2/non-zero"
116
+ },
117
+ {
118
+ "id": "extension/cleanup",
119
+ "entry": "orchestration/extension/cleanup.mjs",
120
+ "kind": "node",
121
+ "purpose": "Remove the extension overlay and exactly the recorded git-exclude entries.",
122
+ "inputs": "--target; env RECIPE_HARNESS_ROOT",
123
+ "outputs": "removes <harness>/extension; exit 0/2"
124
+ },
125
+ {
126
+ "id": "extension/sidepanel-toggle",
127
+ "entry": "orchestration/extension/sidepanel-toggle.sh",
128
+ "kind": "bash",
129
+ "purpose": "Window-mode control for the extension instance: chrome.sidePanel status/open/close/toggle/cycle over the instance's CDP port.",
130
+ "inputs": "<status|open|close|toggle|cycle> --cdp-port --ext-id --agent-dir --settle-ms; env REPO, CDP_PORT, EXT_ID, SETTLE_MS, AGENT_DIR",
131
+ "outputs": "status/progress on stdout; exit 0/1/2"
132
+ },
133
+ {
134
+ "id": "extension/pin-remote-flags",
135
+ "entry": "orchestration/extension/pin-remote-flags.cjs",
136
+ "kind": "lib",
137
+ "purpose": "Pin A/B remote feature-flag variants into an extension manifest _flags before runtime-dist launch.",
138
+ "inputs": "<manifest.json> <KEY=VARIANT[,KEY=VARIANT...]>",
139
+ "outputs": "rewrites manifest._flags.remoteFeatureFlags; exit 0 / throw"
140
+ },
141
+ {
142
+ "id": "extension/readiness",
143
+ "entry": "orchestration/extension/readiness.mjs",
144
+ "kind": "node",
145
+ "purpose": "Health probe for one extension instance: dist entry files + live CDP target, repairs <runtime-dir>/extension.id.",
146
+ "inputs": "--target --cdp-port --json; env RECIPE_RUNTIME_DIR",
147
+ "outputs": "readiness report on stdout; exit 0 ready / non-zero"
148
+ },
149
+ {
150
+ "id": "extension/wallet-fixture-state",
151
+ "entry": "orchestration/extension/wallet-fixture-state.cjs",
152
+ "kind": "node",
153
+ "purpose": "Instance wallet state: generate deterministic state from a fixture, prefill the Chrome profile, seed/validate over CDP.",
154
+ "inputs": "generate|prefill-profile|seed-cdp + flags per usage(); env RECIPE_RUNTIME_DIR",
155
+ "outputs": "--out/--state JSON files; exit 0/1/2"
156
+ },
157
+ {
158
+ "id": "extension/extension-id",
159
+ "entry": "orchestration/extension/extension-id.ts",
160
+ "kind": "module",
161
+ "purpose": "Deterministic CRX id resolution from the loaded dist manifest key (TS module used by the runner CLI).",
162
+ "inputs": "resolveExtensionId(target)",
163
+ "outputs": "extension id string"
164
+ },
165
+ {
166
+ "id": "extension/ensure-ready",
167
+ "entry": "orchestration/extension/ensure-ready.ts",
168
+ "kind": "module",
169
+ "purpose": "Ensure the extension runtime is attachable (TS module used by the runner CLI).",
170
+ "inputs": "ensureExtensionReady(...)",
171
+ "outputs": "readiness result"
172
+ },
173
+ {
174
+ "id": "extension/runtime",
175
+ "entry": "orchestration/extension/runtime.ts",
176
+ "kind": "module",
177
+ "purpose": "Extension runtime prepare/health over CDP (TS module used by the runner CLI).",
178
+ "inputs": "prepareExtensionRuntime/checkExtensionRuntimeHealth",
179
+ "outputs": "runtime state"
180
+ },
181
+ {
182
+ "id": "extension/runtime-decision",
183
+ "entry": "orchestration/extension/runtime-decision.ts",
184
+ "kind": "module",
185
+ "purpose": "Cache/deps baseline + readiness decision (TS module used by the runner CLI).",
186
+ "inputs": "decideExtensionReadiness(...)",
187
+ "outputs": "decision record"
188
+ },
189
+ {
190
+ "id": "mobile/runtime-decision",
191
+ "entry": "orchestration/mobile/runtime-decision.ts",
192
+ "kind": "module",
193
+ "purpose": "Mobile deps + Metro bundle readiness decision (parity with extension runtime-decision).",
194
+ "inputs": "decideMobileReadiness(...)",
195
+ "outputs": "decision record"
196
+ },
197
+ {
198
+ "id": "mobile/deps-markers",
199
+ "entry": "orchestration/mobile/deps-markers.ts",
200
+ "kind": "module",
201
+ "purpose": "MetaMask Mobile product/native marker tables for harness deps-readiness.",
202
+ "inputs": "mobileProductMarkers(platform?)",
203
+ "outputs": "marker path list"
204
+ },
205
+ {
206
+ "id": "core/inject",
207
+ "entry": "orchestration/core/inject.sh",
208
+ "kind": "bash",
209
+ "purpose": "Headless core adapter install: overlay metadata + runner delegate only (no product writes).",
210
+ "inputs": "--target; env RECIPE_HARNESS_ROOT, METAMASK_RUNNER_PROTOCOL_ROOT>FARMSLOT_ROOT",
211
+ "outputs": "<harness>/core/{manifest.json,action-manifest.json,runner/}; exit 0/1/2"
212
+ },
213
+ {
214
+ "id": "core/cleanup",
215
+ "entry": "orchestration/core/cleanup.sh",
216
+ "kind": "bash",
217
+ "purpose": "Remove the core overlay dir (idempotent; nothing to restore).",
218
+ "inputs": "--target; env RECIPE_HARNESS_ROOT",
219
+ "outputs": "removes <harness>/core; exit 0/2"
220
+ },
221
+ {
222
+ "id": "lib/harness-path",
223
+ "entry": "orchestration/lib/harness-path.sh",
224
+ "kind": "lib",
225
+ "purpose": "THE one sourceable lib: harness root/dir + runtime dir resolution with path validation.",
226
+ "inputs": "env RECIPE_HARNESS_ROOT, RECIPE_RUNTIME_DIR (validated relative paths)",
227
+ "outputs": "harness_root / harness_dir / recipe_runtime_dir functions"
228
+ },
229
+ {
230
+ "id": "lib/hash-helpers",
231
+ "entry": "orchestration/lib/hash-helpers.sh",
232
+ "kind": "lib",
233
+ "purpose": "Overlay file hash markers (digest_file/digest_stdin/hash_path) for safe re-install/cleanup.",
234
+ "inputs": "TARGET env var (hash_path)",
235
+ "outputs": "sha256 digests on stdout"
236
+ },
237
+ {
238
+ "id": "lib/json-field",
239
+ "entry": "orchestration/lib/json-field.sh",
240
+ "kind": "lib",
241
+ "purpose": "read_runtime_context_field: dotted-path JSON reader for harness scripts.",
242
+ "inputs": "json path + dotted field",
243
+ "outputs": "field value on stdout"
244
+ },
245
+ {
246
+ "id": "lib/recipe-paths",
247
+ "entry": "orchestration/lib/recipe-paths.mjs",
248
+ "kind": "lib",
249
+ "purpose": "ESM mirror of harness-path defaults/validation for node scripts.",
250
+ "inputs": "env RECIPE_HARNESS_ROOT, RECIPE_RUNTIME_DIR",
251
+ "outputs": "recipeHarnessRoot()/recipeRuntimeDir() exports"
252
+ },
253
+ {
254
+ "id": "lib/activate-repo-node",
255
+ "entry": "orchestration/lib/activate-repo-node.sh",
256
+ "kind": "lib",
257
+ "purpose": "Manager-agnostic Node pin from .nvmrc / .tool-versions for non-interactive yarn/webpack spawns (tmux, nohup).",
258
+ "inputs": "activate_repo_node [target-dir]; tries asdf, fnm, mise, nvm, then matching node on PATH",
259
+ "outputs": "REPO_NODE_BIN, REPO_NODE_PATH_PREFIX; prepends bin dir to PATH; exit 0/1/2"
260
+ },
261
+ {
262
+ "id": "lib/ensure-runner-deps",
263
+ "entry": "orchestration/lib/ensure-runner-deps.sh",
264
+ "kind": "lib",
265
+ "purpose": "Idempotent install of runner npm deps (@farmslot/recipe-harness) for cloned checkouts with no node_modules; uses npm so parent product .yarnrc.yml does not block install.",
266
+ "inputs": "ensure-runner-deps.sh [RUNNER_DIR]; env FARMSLOT_ROOT / METAMASK_RUNNER_PROTOCOL_ROOT optional local link target",
267
+ "outputs": "installed node_modules in RUNNER_DIR; exit 0 when deps ready"
268
+ },
269
+ {
270
+ "id": "lib/resolve-farmslot-ports",
271
+ "entry": "orchestration/lib/resolve-farmslot-ports.sh",
272
+ "kind": "lib",
273
+ "purpose": "Resolve CDP + watcher ports from farmslot pool JSON by repo path, else 6660+N / 9010+N.",
274
+ "inputs": "resolve_extension_runtime_ports <repo>",
275
+ "outputs": "CDP_PORT / WATCHER_PORT / SLOT_ID lines on stdout"
276
+ },
277
+ {
278
+ "id": "lib/path-defaults",
279
+ "entry": "orchestration/lib/path-defaults.json",
280
+ "kind": "data",
281
+ "purpose": "Single source for the default harness root and runtime dir.",
282
+ "inputs": "none",
283
+ "outputs": "recipeHarnessRoot / recipeRuntimeDir defaults"
284
+ },
285
+ {
286
+ "id": "lib/cli-color",
287
+ "entry": "orchestration/lib/cli-color.mjs",
288
+ "kind": "lib",
289
+ "purpose": "Shared ANSI styling for recipe CLI human output (NO_COLOR / TTY aware).",
290
+ "inputs": "import { color, colorLogEvent, ... }",
291
+ "outputs": "styled strings for home, logs, and progress views"
292
+ },
293
+ {
294
+ "id": "lib/cli-home",
295
+ "entry": "orchestration/lib/cli-home.mjs",
296
+ "kind": "lib",
297
+ "purpose": "Recipe CLI home screen and ports output for mm-recipe / mme-recipe wrappers.",
298
+ "inputs": "--adapter extension|mobile --target --cdp-port --watcher-port [--harness-stale] [--json]",
299
+ "outputs": "human home/ports screen or JSON payload on stdout"
300
+ },
301
+ {
302
+ "id": "lib/cli-ux",
303
+ "entry": "orchestration/lib/cli-ux.sh",
304
+ "kind": "lib",
305
+ "purpose": "Shared bash UX helpers: progress, log-tui watch, failure playbooks, harness stale warnings.",
306
+ "inputs": "sourced by bin/mm-recipe and bin/mme-recipe",
307
+ "outputs": "recipe_progress / recipe_watch_rebuild_log / recipe_failure_playbook functions"
308
+ },
309
+ {
310
+ "id": "lib/cli-version",
311
+ "entry": "orchestration/lib/cli-version.mjs",
312
+ "kind": "node",
313
+ "purpose": "Detect stale installed harness scripts vs the active runner revision.",
314
+ "inputs": "check --runner-root --manifest [--installed-sha] [--json]",
315
+ "outputs": "stale boolean + details on stdout/stderr; exit 0"
316
+ },
317
+ {
318
+ "id": "lib/log-tui",
319
+ "entry": "orchestration/lib/log-tui.mjs",
320
+ "kind": "node",
321
+ "purpose": "Compact build-log UX: last N significant events plus pointer to full log.",
322
+ "inputs": "watch|tail|events --log <path> [--events <n>] [--mode compact|full|quiet] [--json]",
323
+ "outputs": "compact TUI on stderr/stdout; watch exits 0 on success pattern / 1 on failure"
324
+ },
325
+ {
326
+ "id": "lib/open-debug",
327
+ "entry": "orchestration/lib/open-debug.mjs",
328
+ "kind": "node",
329
+ "purpose": "Open human-facing debugger UIs for extension CDP or mobile Metro runtimes.",
330
+ "inputs": "--adapter extension|mobile [--cdp-port|--port] [--target page|worker] [--json] [--no-open]",
331
+ "outputs": "debug URL/report on stdout; exit 0/1"
332
+ },
333
+ {
334
+ "id": "lib/progress",
335
+ "entry": "orchestration/lib/progress.mjs",
336
+ "kind": "node",
337
+ "purpose": "Structured progress events for long recipe CLI operations (emit/done).",
338
+ "inputs": "emit|done --verb --phase|--status --message [--elapsed-ms] [--json]",
339
+ "outputs": "human or JSONL progress line on stderr"
340
+ },
341
+ {
342
+ "id": "lib/cli-commands",
343
+ "entry": "orchestration/lib/cli-commands.mjs",
344
+ "kind": "lib",
345
+ "purpose": "Single source of truth for recipe CLI command/flag completion metadata.",
346
+ "inputs": "dump|describe|flags|args|global-flags --adapter extension|mobile|shim",
347
+ "outputs": "completion tokens on stdout for shell scripts"
348
+ },
349
+ {
350
+ "id": "compat-overlays/mobile",
351
+ "entry": "orchestration/compat-overlays/mobile",
352
+ "kind": "compat-overlay",
353
+ "purpose": "Historical-commit replay support: reversible source overlays (e.g. rn81-message-event-source.patch) applied manually/via the recipe-harness skill so pre-RN-0.81 mobile checkouts boot and bridge under the current toolchain.",
354
+ "inputs": "manual `git apply` in the historical product checkout (no in-repo apply logic)",
355
+ "outputs": "patched historical checkout (reversible via git apply -R); overlay path recorded in eval evidence"
356
+ }
357
+ ]
358
+ }
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env bash
2
+ # cleanup.sh — remove the mobile harness overlay from a checkout
3
+ #
4
+ # Purpose:
5
+ # Restores backed-up product files (full installs), removes exactly the
6
+ # .git/info/exclude entries the install recorded, then deletes the harness
7
+ # dir and backup store. Metadata-only installs remove metadata alone.
8
+ #
9
+ # Inputs (flags / env):
10
+ # --target <metamask-mobile> (default $PWD)
11
+ # --allow-managed-changes skip the managed-hash refusal
12
+ # env RECIPE_HARNESS_ROOT
13
+ #
14
+ # Outputs:
15
+ # Removes <harness>/ and backup dir; restores managed product paths.
16
+ # Exit 0 — cleaned; 1 — no backup state / changed managed paths refusal /
17
+ # missing backup; 2 — bad args.
18
+ #
19
+ # Never touches: product files other than the recorded managed paths;
20
+ # .git/info/exclude lines it did not record; product-local cache dirs.
21
+ set -euo pipefail
22
+
23
+ TARGET="$PWD"
24
+ ALLOW_MANAGED_CHANGES=false
25
+ while [ "$#" -gt 0 ]; do
26
+ case "$1" in
27
+ --target) TARGET="$2"; shift 2 ;;
28
+ --allow-managed-changes) ALLOW_MANAGED_CHANGES=true; shift ;;
29
+ -h|--help) echo "Usage: cleanup.sh [--target <metamask-mobile>] [--allow-managed-changes]"; exit 0 ;;
30
+ *) echo "Unknown arg: $1" >&2; exit 2 ;;
31
+ esac
32
+ done
33
+
34
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
35
+ TARGET="$(cd "$TARGET" && pwd)"
36
+ # shellcheck disable=SC1091
37
+ . "$SCRIPT_DIR/../lib/hash-helpers.sh"
38
+ # shellcheck disable=SC1091
39
+ for _hp in "$SCRIPT_DIR/../lib/harness-path.sh"; do
40
+ [ -f "$_hp" ] && { . "$_hp"; break; }
41
+ done
42
+ unset _hp
43
+ if ! command -v harness_root >/dev/null 2>&1; then
44
+ echo "mm-harness: shared lib orchestration/lib/harness-path.sh not found; reinstall the runner." >&2
45
+ exit 1
46
+ fi
47
+ HARNESS_DIR="$(harness_dir "$TARGET" mobile)"
48
+ if GIT_BACKUP_PATH="$(git -C "$TARGET" rev-parse --git-path recipe-harness/mobile/backup 2>/dev/null)"; then
49
+ case "$GIT_BACKUP_PATH" in
50
+ /*) BACKUP_DIR="$GIT_BACKUP_PATH" ;;
51
+ *) BACKUP_DIR="$TARGET/$GIT_BACKUP_PATH" ;;
52
+ esac
53
+ else
54
+ BACKUP_DIR="$HARNESS_DIR/backup-store"
55
+ fi
56
+ if [ ! -f "$BACKUP_DIR/state.env" ] && [ -f "$HARNESS_DIR/backup/state.env" ]; then
57
+ BACKUP_DIR="$HARNESS_DIR/backup"
58
+ fi
59
+ STATE_FILE="$BACKUP_DIR/state.env"
60
+
61
+ remove_recorded_git_exclude_entries() {
62
+ local tracking_file="$1"
63
+ [ -s "$tracking_file" ] || return 0
64
+ local git_dir exclude_file tmp_file
65
+ if ! git_dir="$(git -C "$TARGET" rev-parse --git-dir 2>/dev/null)"; then
66
+ return 0
67
+ fi
68
+ case "$git_dir" in
69
+ /*) ;;
70
+ *) git_dir="$TARGET/$git_dir" ;;
71
+ esac
72
+ exclude_file="$git_dir/info/exclude"
73
+ [ -f "$exclude_file" ] || return 0
74
+ # Remove only the lines THIS install recorded, one occurrence per distinct
75
+ # ledger entry (the appended copy is the last match), so a pre-existing
76
+ # duplicate copy or a stale/duplicate ledger entry never drops a line we did
77
+ # not add this run.
78
+ tmp_file="$(mktemp)"
79
+ awk '
80
+ NR==FNR { if (length($0)) want[$0]=1; next }
81
+ { lines[++n]=$0; if ($0 in want) last[$0]=n }
82
+ END { for (k in last) drop[last[k]]=1; for (i=1;i<=n;i++) if (!(i in drop)) print lines[i] }
83
+ ' "$tracking_file" "$exclude_file" > "$tmp_file"
84
+ mv "$tmp_file" "$exclude_file"
85
+ }
86
+
87
+ if [ -f "$HARNESS_DIR/manifest.json" ] && node -e '
88
+ const fs = require("fs");
89
+ const manifest = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
90
+ process.exit(manifest.installMode === "product-owned" ? 0 : 1);
91
+ ' "$HARNESS_DIR/manifest.json" 2>/dev/null; then
92
+ remove_recorded_git_exclude_entries "$HARNESS_DIR/added-git-exclude"
93
+ rm -rf "$HARNESS_DIR"
94
+ echo "Cleaned mobile recipe harness metadata from $TARGET (product-owned in-app bridge files left untouched)"
95
+ exit 0
96
+ fi
97
+
98
+ if [ ! -f "$STATE_FILE" ]; then
99
+ if [ -f "$HARNESS_DIR/manifest.json" ] && node -e '
100
+ const fs = require("fs");
101
+ const manifest = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
102
+ process.exit(manifest.installMode === "product-owned" ? 0 : 1);
103
+ ' "$HARNESS_DIR/manifest.json" 2>/dev/null; then
104
+ remove_recorded_git_exclude_entries "$HARNESS_DIR/added-git-exclude"
105
+ rm -rf "$HARNESS_DIR"
106
+ echo "Cleaned mobile recipe harness metadata from $TARGET (product-owned in-app bridge files left untouched)"
107
+ exit 0
108
+ fi
109
+ echo "No mobile harness backup found at $STATE_FILE" >&2
110
+ exit 1
111
+ fi
112
+
113
+ while IFS= read -r _line || [ -n "$_line" ]; do
114
+ [[ "$_line" =~ ^[[:space:]]*(#|$) ]] && continue
115
+ _key="${_line%%=*}"
116
+ _val="${_line#*=}"
117
+ case "$_key" in
118
+ AGENTIC_SERVICE_EXISTED|PACKAGE_JSON_EXISTED|NAVIGATION_SERVICE_EXISTED|APP_TSX_EXISTED) ;;
119
+ *) continue ;;
120
+ esac
121
+ export "$_key=$_val"
122
+ done < "$STATE_FILE"
123
+ unset _line _key _val
124
+
125
+ HASH_FILE="$BACKUP_DIR/managed-hashes.tsv"
126
+
127
+ verify_managed_paths_unchanged() {
128
+ if [ ! -f "$HASH_FILE" ]; then
129
+ cat >&2 <<EOF
130
+ Refusing cleanup: no managed hash file found at $HASH_FILE.
131
+ Re-run mobile harness install from the current runner to refresh safety metadata, or restore manually.
132
+ EOF
133
+ exit 1
134
+ fi
135
+ local rel expected actual conflicts=0
136
+ while IFS=$'\t' read -r rel expected; do
137
+ [ -n "$rel" ] || continue
138
+ actual="$(hash_path "$rel")"
139
+ if [ "$actual" != "$expected" ]; then
140
+ echo "Refusing cleanup: managed harness path changed after install: $rel" >&2
141
+ echo " expected: $expected" >&2
142
+ echo " actual: $actual" >&2
143
+ conflicts=1
144
+ fi
145
+ done < "$HASH_FILE"
146
+ if [ "$conflicts" != "0" ]; then
147
+ cat >&2 <<EOF
148
+ Cleanup would restore backups over files that changed after harness install.
149
+ Save/stash those changes, rerun harness install to refresh managed hashes, or restore manually.
150
+ EOF
151
+ exit 1
152
+ fi
153
+ }
154
+
155
+ if [ "$ALLOW_MANAGED_CHANGES" != "true" ]; then
156
+ verify_managed_paths_unchanged
157
+ else
158
+ echo "Allowing cleanup over changed managed harness paths."
159
+ fi
160
+
161
+ restore_path() {
162
+ local rel="$1"
163
+ local existed="$2"
164
+ local target_path="$TARGET/$rel"
165
+ local backup_path="$BACKUP_DIR/$rel"
166
+ if [ "$existed" = "1" ]; then
167
+ if [ ! -e "$backup_path" ]; then
168
+ echo "Missing backup for $rel at $backup_path" >&2
169
+ exit 1
170
+ fi
171
+ rm -rf "$target_path"
172
+ mkdir -p "$(dirname "$target_path")"
173
+ cp -a "$backup_path" "$target_path"
174
+ else
175
+ rm -rf "$target_path"
176
+ fi
177
+ }
178
+
179
+ restore_path "app/dev-tools/AgenticService" "${AGENTIC_SERVICE_EXISTED:-0}"
180
+ if [ "${PACKAGE_JSON_EXISTED+x}" = "x" ]; then
181
+ restore_path "package.json" "$PACKAGE_JSON_EXISTED"
182
+ fi
183
+ restore_path "app/core/NavigationService/NavigationService.ts" "${NAVIGATION_SERVICE_EXISTED:-0}"
184
+ restore_path "app/components/Nav/App/App.tsx" "${APP_TSX_EXISTED:-0}"
185
+
186
+ remove_recorded_git_exclude_entries "$BACKUP_DIR/added-git-exclude"
187
+
188
+ # Leave any product-local cache dirs alone: they are owned by the product
189
+ # checkout, not the harness.
190
+ rm -rf "$HARNESS_DIR"
191
+ rm -rf "$BACKUP_DIR"
192
+ echo "Cleaned mobile recipe harness from $TARGET"
@@ -0,0 +1,21 @@
1
+ /** MetaMask Mobile product markers for deps-readiness partial checks. */
2
+ export const MOBILE_PRODUCT_MARKERS = [
3
+ 'node_modules/.yarn-state.yml',
4
+ 'app/core/InpageBridgeWeb3.js',
5
+ 'docs/assets/termsOfUse.html',
6
+ 'app/util/termsOfUse/termsOfUseContent.ts',
7
+ 'node_modules/.bin/anvil',
8
+ ];
9
+
10
+ export const MOBILE_IOS_NATIVE_MARKERS = ['ios/Podfile.lock'];
11
+ export const MOBILE_ANDROID_NATIVE_MARKERS = ['android/gradle.properties'];
12
+
13
+ export function mobileProductMarkers(platform?: string): string[] {
14
+ const markers = [...MOBILE_PRODUCT_MARKERS];
15
+ const resolved = (platform ?? process.env.PLATFORM ?? process.env.RECIPE_HARNESS_PLATFORM ?? '')
16
+ .trim()
17
+ .toLowerCase();
18
+ if (resolved === 'ios') markers.push(...MOBILE_IOS_NATIVE_MARKERS);
19
+ else if (resolved === 'android') markers.push(...MOBILE_ANDROID_NATIVE_MARKERS);
20
+ return markers;
21
+ }