@deeeed/metamask-harness 0.17.5 → 0.18.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 (132) hide show
  1. package/CHANGELOG.md +872 -0
  2. package/README.md +94 -140
  3. package/adapters/extension/console-tail.mjs +55 -24
  4. package/adapters/extension/ensure-browser.sh +6 -1
  5. package/adapters/extension/inject.mjs +6 -9
  6. package/adapters/extension/launch-browser.cjs +7 -1
  7. package/adapters/extension/launch-webpack.cjs +83 -0
  8. package/adapters/extension/launch.sh +8 -11
  9. package/adapters/extension/lib/chrome-args.cjs +8 -1
  10. package/adapters/extension/lib/macos-focus.cjs +32 -0
  11. package/adapters/extension/live.sh +12 -21
  12. package/adapters/extension/reattach.sh +1 -0
  13. package/adapters/extension/seed-fixture.sh +4 -12
  14. package/adapters/extension/sidepanel-toggle.sh +4 -1
  15. package/adapters/extension/stamp-runtime-title.cjs +58 -0
  16. package/adapters/extension/start-watch.sh +17 -4
  17. package/adapters/extension/stop-viewers.sh +1 -1
  18. package/adapters/extension/sync-webpack-dist.cjs +107 -0
  19. package/adapters/extension/verify.sh +1 -1
  20. package/adapters/manifest.json +53 -37
  21. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +16 -0
  22. package/adapters/mobile/bridge-runtime/console-forwarder.cjs +1 -1
  23. package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +3 -1
  24. package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +2 -3
  25. package/adapters/mobile/cleanup.sh +16 -176
  26. package/adapters/mobile/inject.sh +90 -671
  27. package/adapters/mobile/launch-console-forwarder.cjs +39 -0
  28. package/adapters/mobile/open-device.sh +45 -7
  29. package/adapters/mobile/start-console-forwarder.sh +70 -0
  30. package/adapters/mobile/start-metro.sh +0 -41
  31. package/adapters/mobile/verify.sh +19 -64
  32. package/adapters/mobile/wait-for-bridge.sh +22 -8
  33. package/adapters/shared/resolve-slot-ports-core.mjs +17 -6
  34. package/adapters/shared/resolve-slot-ports.sh +17 -5
  35. package/adapters/shared/update-check-worker.mjs +43 -0
  36. package/bin/mm-harness +21 -2
  37. package/dist/adapters/core/surface.js +4 -1
  38. package/dist/adapters/extension/console-capture.js +95 -0
  39. package/dist/adapters/extension/product-config.js +110 -0
  40. package/dist/adapters/extension/runtime-decision.js +20 -2
  41. package/dist/adapters/extension/surface.js +22 -3
  42. package/dist/adapters/mobile/perps-env.js +43 -3
  43. package/dist/adapters/mobile/prepare.js +39 -7
  44. package/dist/adapters/mobile/surface.js +5 -2
  45. package/dist/adapters/resolve-slot-ports.js +2 -2
  46. package/dist/adapters/slot-ports.js +13 -16
  47. package/dist/adapters.js +56 -16
  48. package/dist/checkout-lock.js +27 -2
  49. package/dist/cli-color.js +19 -0
  50. package/dist/cli-commands.js +1 -1
  51. package/dist/cli.js +7 -14
  52. package/dist/command-contract.js +451 -0
  53. package/dist/command-journal.js +225 -0
  54. package/dist/commands/call.js +170 -50
  55. package/dist/commands/check.js +9 -3
  56. package/dist/commands/completion-candidates.js +20 -13
  57. package/dist/commands/device-target.js +27 -12
  58. package/dist/commands/doctor.js +106 -25
  59. package/dist/commands/fixtures.js +92 -34
  60. package/dist/commands/flows.js +39 -10
  61. package/dist/commands/last.js +52 -0
  62. package/dist/commands/launch/extension.js +38 -15
  63. package/dist/commands/launch/index.js +207 -63
  64. package/dist/commands/list-executables.js +151 -29
  65. package/dist/commands/logs.js +8 -6
  66. package/dist/commands/manifest.js +270 -35
  67. package/dist/commands/parse-args.js +13 -1
  68. package/dist/commands/provision.js +10 -3
  69. package/dist/commands/run-engine.js +435 -105
  70. package/dist/commands/run-report.js +12 -3
  71. package/dist/commands/run.js +355 -50
  72. package/dist/commands/shared.js +75 -3
  73. package/dist/commands/status-probe.js +4 -1
  74. package/dist/commands/status.js +2 -1
  75. package/dist/commands/stop.js +7 -2
  76. package/dist/commands/update.js +16 -28
  77. package/dist/completions-cache.js +1 -1
  78. package/dist/doctor.js +57 -10
  79. package/dist/harness.js +47 -137
  80. package/dist/heal-bounds.js +2 -2
  81. package/dist/json-stream.js +57 -0
  82. package/dist/live-adapter-contract.js +138 -32
  83. package/dist/manifest.js +161 -1
  84. package/dist/mm-harness-cli.js +135 -54
  85. package/dist/paths.js +2 -5
  86. package/dist/recipe-security.js +178 -0
  87. package/dist/run-diagnostics.js +261 -0
  88. package/dist/runner.js +117 -8
  89. package/docs/CONTRIBUTING.md +137 -0
  90. package/docs/QA.md +185 -0
  91. package/docs/RECIPES.md +161 -0
  92. package/docs/SECURITY.md +88 -0
  93. package/library/README.md +4 -0
  94. package/library/actions/core/perps/_controller.mjs +10 -55
  95. package/library/actions/core/perps/read_account.mjs +2 -2
  96. package/library/actions/core/perps/read_orders.mjs +2 -1
  97. package/library/actions/core/perps/read_positions.mjs +2 -1
  98. package/library/actions/core/wallet/list_accounts.mjs +95 -0
  99. package/library/actions/extension/platform/cdp.mjs +1 -0
  100. package/library/actions/extension/wallet/list_accounts.mjs +41 -0
  101. package/library/actions/mobile/wallet/list_accounts.mjs +37 -0
  102. package/library/manifests/core.action-manifest.json +68 -7
  103. package/library/manifests/extension.action-manifest.json +53 -0
  104. package/library/manifests/mobile.action-manifest.json +81 -3
  105. package/library/recipes/runner/action-validation.extension.recipe.json +8 -1
  106. package/library/recipes/runner/action-validation.mobile.recipe.json +8 -1
  107. package/library/recipes/runner/smoke.core.recipe.json +27 -0
  108. package/library/recipes/wallet/smoke.extension.recipe.json +42 -0
  109. package/library/recipes/wallet/smoke.mobile.recipe.json +42 -0
  110. package/package.json +12 -5
  111. package/scripts/completions.sh +7 -7
  112. package/scripts/validate-human-outcomes.mjs +169 -0
  113. package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +0 -185
  114. package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +0 -1662
  115. package/adapters/mobile/overlay/compat/README.md +0 -28
  116. package/adapters/mobile/overlay/compat/rn81-message-event-source.patch +0 -42
  117. package/adapters/shared/resolve-farmslot-ports-core.mjs +0 -3
  118. package/adapters/shared/resolve-farmslot-ports.mjs +0 -5
  119. package/adapters/shared/resolve-farmslot-ports.sh +0 -7
  120. package/docs/ADAPTER-SURFACE.md +0 -119
  121. package/docs/CHEATSHEET.md +0 -61
  122. package/docs/CLI-SPEC.md +0 -1098
  123. package/docs/CODE-MAP.md +0 -62
  124. package/docs/DEBUG-HANDOVER.md +0 -36
  125. package/docs/MENTAL-MODEL.md +0 -295
  126. package/docs/UX-PRINCIPLES.md +0 -64
  127. package/docs/architecture.md +0 -398
  128. package/docs/live-adapter-contract.md +0 -188
  129. package/docs/package-boundaries.md +0 -47
  130. package/docs/perps-flow-catalog.md +0 -235
  131. package/docs/recipe-libraries.md +0 -301
  132. package/docs/runtime-file-conventions.md +0 -36
@@ -1,28 +0,0 @@
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 fixes.
11
- - How it is applied: MANUALLY (no automatic apply logic in this repo).
12
- The operator or the `/recipe-harness` skill applies the patch reversibly
13
- before a historical rebuild (`git apply <patch>` in the product checkout,
14
- `git apply -R` to remove) and records the overlay path in validation
15
- evidence. `adapters/mobile/inject.sh` does NOT apply these.
16
-
17
- Kept in the external runner repository, not Farmslot root scripts, so a
18
- `/recipe-harness` skill can apply the same reversible overlay before a
19
- historical rebuild and record the overlay path in validation evidence.
20
-
21
- Listed in adapters/manifest.json (kind: compat-overlay) so the doctor
22
- verifies the surface and this directory is never flagged as unused again.
23
-
24
- ## Patches
25
-
26
- - `rn81-message-event-source.patch`: adds a read-only `MessageEvent.prototype.source`
27
- getter for React Native 0.81 historical checkouts whose bundled polyfill omits
28
- it while CDP websocket clients expect browser-compatible `MessageEvent` shape.
@@ -1,42 +0,0 @@
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);
@@ -1,3 +0,0 @@
1
- // Back-compat shim: the port-resolution core is now resolve-slot-ports-core.mjs.
2
- // Re-exports it verbatim for one release so importers of the old path keep resolving.
3
- export * from './resolve-slot-ports-core.mjs';
@@ -1,5 +0,0 @@
1
- #!/usr/bin/env node
2
- // Back-compat shim: this leaf is now resolve-slot-ports.mjs. Delegates to it for one
3
- // release so `node resolve-farmslot-ports.mjs <fn> <repo>` keeps working (the new CLI
4
- // reads the same argv positions on import).
5
- import './resolve-slot-ports.mjs';
@@ -1,7 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Back-compat shim: this wrapper is now resolve-slot-ports.sh. Sources it for one
3
- # release so old callers keep the same sourced function names (including the
4
- # resolve_farmslot_ports_by_repo alias defined there).
5
- _SHIM_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- # shellcheck disable=SC1091
7
- . "$_SHIM_DIR/resolve-slot-ports.sh"
@@ -1,119 +0,0 @@
1
- # The adapter surface — one seam for per-platform behavior
2
-
3
- `mm-harness` runs against three platforms (mobile | extension | core). The
4
- danger is that every command re-derives "what does this platform do?" with its
5
- own `if (adapter === 'mobile') … else if (adapter === 'extension') …` ladder.
6
- When it does, a platform gets forgotten in one command but not another — the
7
- class of bug where `doctor` reported a live runtime section for mobile only,
8
- `stop` refused every non-mobile adapter, and `logs` knew a single extension log
9
- file instead of all three. Those are *platform-blind* commands.
10
-
11
- The **adapter surface** is the fix: one interface per platform, resolved through
12
- a registry, that owns the behavior a command would otherwise branch on.
13
-
14
- ## The interface
15
-
16
- `src/adapters/surface.ts` defines `AdapterSurface` and the registry
17
- `getAdapterSurface(adapter)`. Each platform ships one implementation:
18
-
19
- - `src/adapters/mobile/surface.ts`
20
- - `src/adapters/extension/surface.ts`
21
- - `src/adapters/core/surface.ts`
22
-
23
- ```ts
24
- interface AdapterSurface {
25
- readonly adapter: MetaMaskRecipeAdapter;
26
- readonly headless: boolean; // core runs no app/dev server
27
- resolveSlotPorts(target: string): void; // context > pool > formula (no-op for core)
28
- runtimeStatus(target: string): Promise<AdapterRuntimeStatus>; // read-only readiness for doctor
29
- devServer: {
30
- describe(): string; // "Metro" | "webpack watcher" | "no dev server (headless)"
31
- stop(target: string): AdapterDevServerStop; // idempotent, slot-scoped; headless = teach
32
- };
33
- logSources(target: string): AdapterLogSource[]; // ordered candidate log files (empty for core)
34
- hints: { launch: string; relaunch: string }; // platform-phrased Next: hints
35
- }
36
- ```
37
-
38
- `runtimeStatus` returns a normalized shape so `doctor` renders one line the same
39
- way for every platform:
40
-
41
- ```ts
42
- interface AdapterRuntimeStatus {
43
- decision: string;
44
- reasonCode?: string;
45
- reasons: string[];
46
- deps?: string;
47
- devServer?: { label: string; status: string }; // absent for headless core
48
- }
49
- ```
50
-
51
- The implementations are thin: they delegate to the readiness/port plumbing that
52
- already existed (`decideExtensionReadiness`, `mobileRuntimeStatus`, the slot-port
53
- resolvers and the webpack-watcher stop, all re-homed to
54
- `src/adapters/slot-ports.ts`). The surface is an organizing seam, not a rewrite.
55
-
56
- ## The rule
57
-
58
- **A command never branches on adapter for behavior the surface owns.**
59
-
60
- - Do not write `if (adapter === 'core')` — ask `surface.headless`.
61
- - Do not write `adapter === 'mobile' ? metroPorts() : extensionPorts()` — call
62
- `surface.resolveSlotPorts(target)`.
63
- - Do not print `adapter === 'mobile' ? 'mm-harness launch ios' : 'mm-harness
64
- launch'` — use `surface.hints.launch`.
65
-
66
- A new platform behavior is added by **extending the surface** (a new member on
67
- the interface plus its three implementations), never by adding another branch to
68
- a command. TypeScript then makes it impossible to ship a platform that forgot the
69
- new member, because each implementation is annotated `: AdapterSurface`.
70
-
71
- What the surface deliberately does **not** own: a command may still branch on
72
- adapter for a *mechanism* that is genuinely platform-specific and not part of the
73
- interface — e.g. `fixtures set` uses a shell arm on mobile and the engine path on
74
- extension. Those branches select a mechanism; they never re-derive readiness,
75
- ports, log locations, dev-server lifecycle, or Next: phrasing, which are the
76
- surface's responsibility.
77
-
78
- ## Migration status
79
-
80
- Every command that used to branch on adapter now resolves through the surface:
81
-
82
- | command | surface-backed | uses |
83
- | --- | --- | --- |
84
- | `doctor` | yes | `resolveSlotPorts` + `runtimeStatus` (mobile/extension/core runtime section) |
85
- | `launch` | yes | `resolveSlotPorts` |
86
- | `stop` | yes | `resolveSlotPorts` + `devServer.stop` (+ headless teaching) |
87
- | `logs` | yes | `logSources` + `hints.launch` + `headless` |
88
- | `debug` | yes | `headless` + `hints.relaunch` (core teaching); flag semantics stay per-command |
89
- | `fixtures` | yes | `headless` + `hints` (retry/launch); the set *mechanism* stays per-platform |
90
- | `run` / `call` | n/a | engine path; core-headless is handled by the heal contract, not the surface |
91
- | `flows` | no (by design) | recipe-library flows are adapter-global; not a platform-owned behavior |
92
- | `completion-candidates` | partial | `actions` scope to the detected checkout adapter; `flows` are adapter-global |
93
-
94
- `flows` is intentionally not surface-backed: a recipe-library flow can compose
95
- actions across platforms, so flows are adapter-global by design rather than a
96
- platform-blind gap. `completion-candidates actions` already resolves the adapter
97
- from the checkout context (cwd/`--target`); only the adapter-global `flows`
98
- candidates are unscoped, matching the flows model.
99
-
100
- ## How this composes with the UX principles
101
-
102
- `docs/UX-PRINCIPLES.md` principle 1 (*Context-aware by default* — "output is
103
- scoped to the platform… help, flag lists, and completion candidates shrink to
104
- what applies here") states the intent. The adapter surface is its **enforcement
105
- mechanism**: a command that resolves platform behavior through the surface is
106
- context-aware by construction, and one that hand-rolls an adapter ladder is the
107
- exact failure principle 1 warns against. When adding a command or output path,
108
- satisfy principle 1 by going through the surface.
109
-
110
- ## Adding a platform behavior — checklist
111
-
112
- 1. Add the member to `AdapterSurface` in `src/adapters/surface.ts`.
113
- 2. Implement it in all three `src/adapters/*/surface.ts` (TypeScript will not
114
- compile until you do).
115
- 3. Have the command call `getAdapterSurface(adapter).<member>` instead of
116
- branching.
117
- 4. Cover the closed blind spot with a contract test (see
118
- `tests/contract/adapter-surface.test.sh`), and keep the registry-completeness
119
- assertion green.
@@ -1,61 +0,0 @@
1
- # mm-harness — user cheatsheet
2
-
3
- `mm-harness <command> [target] [flags]` · Run from inside any MetaMask checkout · Platform auto-detected
4
-
5
- ---
6
-
7
- ## Daily loop
8
-
9
- | Situation | Command |
10
- |---|---|
11
- | Start / relaunch iOS | `mm-harness launch ios` |
12
- | Start / relaunch Android | `mm-harness launch android` |
13
- | Launch extension (fullscreen) | `mm-harness launch` |
14
- | Launch extension in sidepanel | `mm-harness launch --sidepanel` |
15
- | Native code changed — rebuild first | `mm-harness launch ios --build` |
16
- | Tail Metro / webpack logs | `mm-harness logs` |
17
- | Open DevTools / RN inspector | `mm-harness debug` |
18
- | Seed wallet from fixture — no typing | `mm-harness fixtures set` |
19
- | Refresh wallet fixture files on slot | `mm-harness fixtures sync` |
20
-
21
- `launch` auto-installs the overlay on first use.
22
- `fixtures set` reads the password **from** the fixture — never typed.
23
-
24
- ---
25
-
26
- ## Proof loop
27
-
28
- ```
29
- actions → call <action> → flows → run recipe.json --plan → run recipe.json
30
- ```
31
-
32
- | Command | What it does |
33
- |---|---|
34
- | `mm-harness actions` | Action vocabulary for this adapter |
35
- | `mm-harness call unlock` | One action through the real engine (fuzzy name ok) |
36
- | `mm-harness flows` | Reusable flows (personal > team > canonical) |
37
- | `mm-harness run recipe.json --plan` | Validate + print plan, no device touched; exit 5 if invalid |
38
- | `mm-harness run recipe.json` | Execute + write evidence (summary / trace / artifacts) |
39
-
40
- ---
41
-
42
- ## Health
43
-
44
- | Command | What it does |
45
- |---|---|
46
- | `mm-harness doctor` | Full readiness check — fixture, runtime context, overlay. No launch. |
47
- | `mm-harness doctor --fix` | Repair overlay + runtime context without launching the app. |
48
- | `mm-harness verify` | Check overlay/runtime is present and healthy. No launch. |
49
- | `mm-harness cleanup` | Remove the overlay and restore the checkout. |
50
-
51
- ---
52
-
53
- ## For agents and scripts
54
-
55
- **`--json`** — machine-readable output on every command; includes `recovered[]`, `mutations[]`, `schemaVersion`.
56
-
57
- **`--heal`** — `off` (fail fast, repro-preserving) · `infra-only` (heal transport, never wallet; `run`/`call` default) · `auto` (auto-ensure overlay + heal; `launch` default).
58
-
59
- **Exit codes** — `0` success · `1` recipe/action failed · `2` bad args / missing target · `5` validation failure (fix recipe).
60
-
61
- **Tab completion** — `mm-harness completions install` prints the lines to add to `~/.zshrc` / `~/.bashrc`.