@deeeed/metamask-harness 0.17.5 → 0.19.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 +1059 -0
- package/README.md +91 -140
- package/adapters/core/inject.sh +1 -6
- package/adapters/extension/console-tail.mjs +55 -24
- package/adapters/extension/ensure-browser.sh +6 -1
- package/adapters/extension/inject.mjs +7 -13
- package/adapters/extension/launch-browser.cjs +7 -1
- package/adapters/extension/launch-webpack.cjs +83 -0
- package/adapters/extension/launch.sh +8 -11
- package/adapters/extension/lib/chrome-args.cjs +8 -1
- package/adapters/extension/lib/macos-focus.cjs +32 -0
- package/adapters/extension/live.sh +12 -21
- package/adapters/extension/reattach.sh +1 -0
- package/adapters/extension/seed-fixture.sh +4 -12
- package/adapters/extension/sidepanel-toggle.sh +4 -1
- package/adapters/extension/stamp-runtime-title.cjs +58 -0
- package/adapters/extension/start-watch.sh +17 -4
- package/adapters/extension/stop-viewers.sh +1 -1
- package/adapters/extension/sync-webpack-dist.cjs +107 -0
- package/adapters/extension/verify.sh +2 -2
- package/adapters/manifest.json +53 -37
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +16 -0
- package/adapters/mobile/bridge-runtime/console-forwarder.cjs +1 -1
- package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +3 -1
- package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +2 -3
- package/adapters/mobile/cleanup.sh +16 -176
- package/adapters/mobile/inject.sh +91 -671
- package/adapters/mobile/launch-console-forwarder.cjs +39 -0
- package/adapters/mobile/open-device.sh +45 -7
- package/adapters/mobile/start-console-forwarder.sh +70 -0
- package/adapters/mobile/start-metro.sh +0 -41
- package/adapters/mobile/verify.sh +34 -83
- package/adapters/mobile/wait-for-bridge.sh +22 -8
- package/adapters/shared/harness-source-fingerprint.mjs +14 -12
- package/adapters/shared/resolve-slot-ports-core.mjs +17 -6
- package/adapters/shared/resolve-slot-ports.sh +17 -5
- package/adapters/shared/update-check-worker.mjs +43 -0
- package/bin/mm-harness +21 -2
- package/dist/adapters/core/surface.js +4 -1
- package/dist/adapters/extension/console-capture.js +95 -0
- package/dist/adapters/extension/product-config.js +110 -0
- package/dist/adapters/extension/runtime-decision.js +20 -2
- package/dist/adapters/extension/surface.js +22 -3
- package/dist/adapters/harness-freshness.js +49 -0
- package/dist/adapters/mobile/perps-env.js +43 -3
- package/dist/adapters/mobile/prepare.js +39 -7
- package/dist/adapters/mobile/surface.js +5 -2
- package/dist/adapters/resolve-slot-ports.js +2 -2
- package/dist/adapters/slot-ports.js +13 -16
- package/dist/adapters.js +56 -16
- package/dist/checkout-lock.js +27 -2
- package/dist/cli-color.js +19 -0
- package/dist/cli-commands.js +1 -1
- package/dist/cli.js +7 -18
- package/dist/command-contract.js +462 -0
- package/dist/command-journal.js +263 -0
- package/dist/commands/call.js +252 -57
- package/dist/commands/check.js +10 -4
- package/dist/commands/completion-candidates.js +17 -22
- package/dist/commands/device-target.js +27 -12
- package/dist/commands/doctor.js +106 -25
- package/dist/commands/fixtures.js +142 -35
- package/dist/commands/last.js +60 -0
- package/dist/commands/launch/extension.js +40 -17
- package/dist/commands/launch/index.js +207 -63
- package/dist/commands/launch/mobile.js +2 -0
- package/dist/commands/list-executables.js +187 -29
- package/dist/commands/logs.js +8 -6
- package/dist/commands/manifest.js +286 -35
- package/dist/commands/parse-args.js +68 -4
- package/dist/commands/provision.js +10 -4
- package/dist/commands/run-engine.js +772 -264
- package/dist/commands/run-report.js +12 -3
- package/dist/commands/run.js +378 -85
- package/dist/commands/shared.js +76 -4
- package/dist/commands/status-probe.js +4 -1
- package/dist/commands/status.js +2 -1
- package/dist/commands/stop.js +7 -2
- package/dist/commands/update.js +16 -28
- package/dist/completions-cache.js +1 -1
- package/dist/doctor.js +57 -10
- package/dist/harness.js +47 -137
- package/dist/heal-bounds.js +7 -2
- package/dist/json-stream.js +57 -0
- package/dist/live-adapter-contract.js +138 -32
- package/dist/manifest.js +161 -1
- package/dist/mm-harness-cli.js +146 -73
- package/dist/paths.js +2 -5
- package/dist/recipe-security.js +178 -0
- package/dist/run-diagnostics.js +261 -0
- package/dist/run-recording.js +1 -1
- package/dist/runner.js +140 -9
- package/docs/CONTRIBUTING.md +136 -0
- package/docs/QA.md +184 -0
- package/docs/RECIPES.md +122 -0
- package/docs/SECURITY.md +88 -0
- package/library/README.md +7 -3
- package/library/actions/core/perps/_controller.mjs +43 -56
- package/library/actions/core/perps/assert_orders.mjs +6 -7
- package/library/actions/core/perps/assert_positions.mjs +6 -7
- package/library/actions/core/perps/close_orders.mjs +2 -0
- package/library/actions/core/perps/close_positions.mjs +2 -0
- package/library/actions/core/perps/ensure_orders.mjs +4 -2
- package/library/actions/core/perps/ensure_positions.mjs +4 -2
- package/library/actions/core/perps/place_order.mjs +7 -3
- package/library/actions/core/perps/read_account.mjs +2 -2
- package/library/actions/core/perps/read_orders.mjs +2 -1
- package/library/actions/core/perps/read_positions.mjs +2 -1
- package/library/actions/core/wallet/list_accounts.mjs +95 -0
- package/library/actions/extension/perps/assert_orders.mjs +2 -1
- package/library/actions/extension/perps/assert_positions.mjs +2 -1
- package/library/actions/extension/perps/perps.mjs +43 -14
- package/library/actions/extension/platform/cdp.mjs +1 -0
- package/library/actions/extension/wallet/list_accounts.mjs +41 -0
- package/library/actions/mobile/perps/assert_orders.mjs +2 -1
- package/library/actions/mobile/perps/assert_positions.mjs +2 -1
- package/library/actions/mobile/perps/perps.mjs +40 -12
- package/library/actions/mobile/wallet/list_accounts.mjs +37 -0
- package/library/library.json +1 -1
- package/library/manifests/core.action-manifest.json +1214 -396
- package/library/manifests/extension.action-manifest.json +1635 -728
- package/library/manifests/mobile.action-manifest.json +1740 -727
- package/library/recipes/app/lifecycle.android-smoke.mobile.recipe.json +63 -81
- package/library/recipes/perps/clean-market-testnet.core.recipe.json +44 -0
- package/library/recipes/perps/clean-market-testnet.recipe.json +49 -0
- package/library/recipes/perps/lifecycle.recipe.json +136 -180
- package/library/recipes/perps/order-lifecycle.core.recipe.json +71 -67
- package/library/recipes/perps/performance.background-resume.mobile.recipe.json +51 -67
- package/library/recipes/perps/performance.cold-start.mobile.recipe.json +51 -67
- package/library/recipes/perps/performance.mobile.recipe.json +37 -51
- package/library/recipes/perps/performance.warm-start.mobile.recipe.json +44 -59
- package/library/recipes/perps/read-markets.core.recipe.json +29 -31
- package/library/recipes/perps/smoke.core.recipe.json +29 -32
- package/library/recipes/perps/smoke.extension.recipe.json +41 -44
- package/library/recipes/perps/smoke.mobile.recipe.json +42 -44
- package/library/recipes/perps/trading-lifecycle.core.recipe.json +69 -65
- package/library/recipes/runner/action-validation.extension.recipe.json +312 -398
- package/library/recipes/runner/action-validation.mobile.recipe.json +316 -402
- package/library/recipes/runner/smoke.core.recipe.json +25 -0
- package/library/recipes/runner/smoke.extension.recipe.json +23 -24
- package/library/recipes/runner/smoke.mobile.recipe.json +23 -24
- package/library/recipes/wallet/smoke.extension.recipe.json +40 -0
- package/library/recipes/wallet/smoke.mobile.recipe.json +40 -0
- package/package.json +12 -5
- package/scripts/completions.sh +8 -11
- package/scripts/validate-human-outcomes.mjs +169 -0
- package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +0 -185
- package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +0 -1662
- package/adapters/mobile/overlay/compat/README.md +0 -28
- package/adapters/mobile/overlay/compat/rn81-message-event-source.patch +0 -42
- package/adapters/shared/resolve-farmslot-ports-core.mjs +0 -3
- package/adapters/shared/resolve-farmslot-ports.mjs +0 -5
- package/adapters/shared/resolve-farmslot-ports.sh +0 -7
- package/dist/adapters/extension/harness-freshness.js +0 -39
- package/dist/commands/flows.js +0 -62
- package/docs/ADAPTER-SURFACE.md +0 -119
- package/docs/CHEATSHEET.md +0 -61
- package/docs/CLI-SPEC.md +0 -1098
- package/docs/CODE-MAP.md +0 -62
- package/docs/DEBUG-HANDOVER.md +0 -36
- package/docs/MENTAL-MODEL.md +0 -295
- package/docs/UX-PRINCIPLES.md +0 -64
- package/docs/architecture.md +0 -398
- package/docs/live-adapter-contract.md +0 -188
- package/docs/package-boundaries.md +0 -47
- package/docs/perps-flow-catalog.md +0 -235
- package/docs/recipe-libraries.md +0 -301
- package/docs/runtime-file-conventions.md +0 -36
- package/library/flows/perps.flows.json +0 -64
package/docs/CODE-MAP.md
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# Code map — where things live and how a command flows
|
|
2
|
-
|
|
3
|
-
One page for humans. The contracts live in docs/UX-PRINCIPLES.md and
|
|
4
|
-
docs/ADAPTER-SURFACE.md; this is the geography.
|
|
5
|
-
|
|
6
|
-
## How a command flows
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
bin/mm-harness bash front door: MM_HARNESS_BIN dev/prod switch,
|
|
10
|
-
│ dist-vs-src selection (dist wins when present;
|
|
11
|
-
│ stale-dist warning), deps ensure
|
|
12
|
-
▼
|
|
13
|
-
src/mm-harness-cli.ts commander surface: grouped colored help, per-command
|
|
14
|
-
│ --help, retired-name teaching; delegates in-process
|
|
15
|
-
▼
|
|
16
|
-
src/cli.ts parse + dispatch ONLY — no verb logic lives here
|
|
17
|
-
│
|
|
18
|
-
├── src/commands/<verb>.ts one module per verb (doctor, stop, call, run,
|
|
19
|
-
│ │ provision, fixtures, flows, logs, debug, …)
|
|
20
|
-
│ ▼
|
|
21
|
-
│ src/adapters/surface.ts AdapterSurface registry — per-platform behavior
|
|
22
|
-
│ │ (ports, runtime status, dev server, log sources)
|
|
23
|
-
│ ▼
|
|
24
|
-
│ src/adapters/{mobile,extension,core}/ TS logic per platform
|
|
25
|
-
│
|
|
26
|
-
└── src/harness.ts overlay lifecycle (install/verify/cleanup) — writes
|
|
27
|
-
│ the per-checkout overlay + runner delegate
|
|
28
|
-
▼
|
|
29
|
-
adapters/ SHELL LEAVES (repo root — not src/adapters!):
|
|
30
|
-
mobile/ extension/ single-OS-op scripts the TS layer spawns
|
|
31
|
-
core/ shared/ (simctl/adb/tmux/metro/webpack lifecycle)
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## The two `adapters/` directories
|
|
35
|
-
|
|
36
|
-
- `adapters/` (repo root) — executable shell leaves. Thin, OS-facing, spawned by TS.
|
|
37
|
-
- `src/adapters/` — TypeScript platform logic behind the AdapterSurface.
|
|
38
|
-
Rule: logic/decisions in TS; a leaf only executes. A leaf converts to TS only when
|
|
39
|
-
it starts making decisions (see backlog ruling), never as a campaign.
|
|
40
|
-
|
|
41
|
-
## Other roots
|
|
42
|
-
|
|
43
|
-
- `library/` — recipe library: actions (`library/actions/<adapter>/…`, executable
|
|
44
|
-
action modules — importing one RUNS it, see library/README.md), flows, recipes.
|
|
45
|
-
- `tests/contract/` — hermetic bash contract tests (PATH-stubbed OS tools). The
|
|
46
|
-
launch-leaf-flags test enforces composer↔leaf flag agreement.
|
|
47
|
-
- `dist/` — esbuild output; the ONLY thing published runs. gitignored; in a source
|
|
48
|
-
checkout it SHADOWS src when present (bin warns when it goes stale).
|
|
49
|
-
- Per-checkout runtime state lives in the TARGET repo: `temp/recipe/runtime/`
|
|
50
|
-
(context, logs, wallet fixture) and `temp/recipe/harness/<adapter>/` (overlay +
|
|
51
|
-
runner delegate pinned to the installing bin via `.runner-source`).
|
|
52
|
-
|
|
53
|
-
## Adding things
|
|
54
|
-
|
|
55
|
-
- **A verb**: module in `src/commands/`, register in `src/cli.ts` dispatch + the
|
|
56
|
-
commander metadata in `src/mm-harness-cli.ts` (help group), contract test.
|
|
57
|
-
- **A flag**: parse in the verb module; if it reaches a leaf, the leaf's parser
|
|
58
|
-
must accept it (launch-leaf-flags test will fail otherwise) — or pass via env.
|
|
59
|
-
- **A leaf**: shell under `adapters/<platform>/`, spawned via the shared spawn
|
|
60
|
-
helpers (never raw exec), contract test with PATH stubs, errors teach escape.
|
|
61
|
-
- **A platform behavior**: extend the AdapterSurface, implement per platform —
|
|
62
|
-
verbs must not branch on adapter for surface-owned behavior.
|
package/docs/DEBUG-HANDOVER.md
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# Extension debugger handover
|
|
2
|
-
|
|
3
|
-
## Objective
|
|
4
|
-
|
|
5
|
-
Make `mm-harness debug` open the normal Chrome DevTools console attached to the already-running extension page in the current slot. Do not claim success from a URL or JSON response alone.
|
|
6
|
-
|
|
7
|
-
## Acceptance
|
|
8
|
-
|
|
9
|
-
1. Start an existing slot runtime with `mm-harness launch --verify`.
|
|
10
|
-
2. Run `mm-harness debug` without relaunching the slot.
|
|
11
|
-
3. Confirm the visible DevTools Console is attached to the existing `chrome-extension://.../home.html#/` target.
|
|
12
|
-
4. Run a harmless console expression and observe its result.
|
|
13
|
-
5. Confirm the debugger remains connected after the extension watcher settles.
|
|
14
|
-
6. Repeat on two isolated extension slots.
|
|
15
|
-
|
|
16
|
-
## Failed attempts (do not repeat blindly)
|
|
17
|
-
|
|
18
|
-
This investigation repeatedly reported machine success without proving the visible UI. The following approaches failed:
|
|
19
|
-
|
|
20
|
-
1. Open the target's hosted `devtoolsFrontendUrl` (`chrome-devtools-frontend.appspot.com`) with macOS `open`. This could select the user's default Chrome profile; when offline it opened an empty tab with `ERR_INTERNET_DISCONNECTED`.
|
|
21
|
-
2. Add `--remote-allow-origins=https://chrome-devtools-frontend.appspot.com`. This fixed one observed HTTP 403 origin rejection but did not make the visible frontend reliable.
|
|
22
|
-
3. Open the hosted URL through the slot profile using `open -na`. It still produced a separate disconnected DevTools tab.
|
|
23
|
-
4. Create a tab through the slot CDP `/json/new` endpoint using `devtools://devtools/bundled/inspector.html?...`. The tab was created, but the visible UI still reported `Debugging connection was closed`.
|
|
24
|
-
5. Add `devtools://devtools` to `--remote-allow-origins`. Direct CDP to the extension target still worked, but the human DevTools UI was not proven connected.
|
|
25
|
-
6. Testing the local checkout while the user invoked the globally installed command caused false confidence: the global command was running a different installation. The global install was temporarily overwritten with unreleased local code; do not assume the published version contains these changes.
|
|
26
|
-
|
|
27
|
-
Screenshots showed the exact failure: a DevTools tab exists, but displays `Debugging connection was closed — WebSocket disconnected`. Direct CDP to the extension page succeeds, so target discovery is not the failure; the human DevTools frontend attachment/lifecycle remains unresolved.
|
|
28
|
-
|
|
29
|
-
## Constraints
|
|
30
|
-
|
|
31
|
-
- Do not open an unrelated/default Chrome profile.
|
|
32
|
-
- Do not silently fall back to another tab and report success.
|
|
33
|
-
- Keep the extension target unchanged.
|
|
34
|
-
- Do not modify product code or commit until the visible acceptance steps pass.
|
|
35
|
-
- Test the actual human UI, not only `--json`, `/json/list`, or a raw CDP handshake.
|
|
36
|
-
- Never report `opened: true` or a present `/json/list` target as proof that the visible DevTools console is attached.
|
package/docs/MENTAL-MODEL.md
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
# mm-harness — Mental Model (review first)
|
|
2
|
-
|
|
3
|
-
Read this before the code. It is the before→after map for the CLI refactor. Every
|
|
4
|
-
"today" command below is real (from `bin/mm-recipe`, `bin/mme-recipe`,
|
|
5
|
-
`runner/src/cli.ts`, and the `recipe-harness` skill) — nothing invented.
|
|
6
|
-
|
|
7
|
-
> Skimmable overview. The detailed contract — a complete capability inventory
|
|
8
|
-
> (every verb, with a fate), a per-verb spec, the caller audit, and the env-var
|
|
9
|
-
> audit — is in [CLI-SPEC.md](CLI-SPEC.md).
|
|
10
|
-
|
|
11
|
-
## The model in one paragraph
|
|
12
|
-
|
|
13
|
-
**`mm-harness` is built for the agent but easy for the human to use and
|
|
14
|
-
understand.** It is the one front door for the whole recipe loop. The agent gets
|
|
15
|
-
full depth (explicit flags, `--json`, ports, build tiers — machine-grade
|
|
16
|
-
determinism); the human gets short verbs, positional targets, good defaults,
|
|
17
|
-
completions, and teaching help/errors. Under it: the **engine** is
|
|
18
|
-
`@farmslot/recipe-harness` (generic graph execution, adapters, recording, CLI);
|
|
19
|
-
the **runner** (this repo) is the thin **MetaMask adapter** layer (manifests,
|
|
20
|
-
`metamask.*` live adapters, orchestration); the **runtime overlay** is the set of
|
|
21
|
-
files the tool installs into a target checkout (`install`/`verify`/`cleanup`).
|
|
22
|
-
The runner never re-implements engine logic — it imports it. The agent
|
|
23
|
-
composition loop is the harness's thesis made concrete: **discover** actions and
|
|
24
|
-
browse flows (`actions --json` / `flows --json`) → **call** one action in
|
|
25
|
-
isolation to verify it (`call <action> --json`) → **compose** a `recipe.json` →
|
|
26
|
-
**plan** before any device is touched (`run --plan`) → **run** → review
|
|
27
|
-
evidence (`summary.json` / `trace.json`). `run --plan` closes the loop: adapter-aware
|
|
28
|
-
validation (action existence, platform support, fixture preconditions) exits fast
|
|
29
|
-
with a reviewable plan artifact — wrong recipes fail before any device is touched.
|
|
30
|
-
|
|
31
|
-
## Organizing rule (Arthur)
|
|
32
|
-
|
|
33
|
-
Identify the MAIN commands a human types daily, then each subcommand — always
|
|
34
|
-
optimizing "how simple for the human," with advanced options for the agent and
|
|
35
|
-
good defaults for easy typing. Enforced rules, visible in every table below:
|
|
36
|
-
|
|
37
|
-
- **Grammar:** `mm-harness <verb> [target] [flags]`. Target is a positional
|
|
38
|
-
(`ios` | `android` | `extension`) — the human form. The equivalent explicit
|
|
39
|
-
flag (`--platform …`) is the agent form.
|
|
40
|
-
- **Depth lives in FLAGS, never in extra command names.** If a daily task needs
|
|
41
|
-
>1 flag (or >1 step) for a human, the default is wrong — a `[DEFAULT-GAP]`.
|
|
42
|
-
- **No env-var prefixes for humans.** `VAR=x mm-harness …` is agent/CI syntax
|
|
43
|
-
only; a human-typed value that has no flag/config home is an `[ENV-GAP]`.
|
|
44
|
-
- **One bin, clean break.** End state has exactly one command, `mm-harness`. The
|
|
45
|
-
`metamask-recipe` / `mm-recipe` / `mme-recipe` names and the `harness <verb>`
|
|
46
|
-
subcommand form are REMOVED in the same coordinated wave; their capabilities
|
|
47
|
-
live at their final `mm-harness` home (Part 2 of the spec).
|
|
48
|
-
- **A verb's most common action is its default action.** `mm-harness flows` lists;
|
|
49
|
-
`mm-harness flows promote` is the explicit subcommand. Never force the user to
|
|
50
|
-
type `list` when listing is what the verb does by default.
|
|
51
|
-
- **Direct action names are not top-level verbs (REJECTED).** `mm-harness unlock`
|
|
52
|
-
is rejected — an open action vocabulary collides with the verb namespace; hot
|
|
53
|
-
actions get deliberately promoted to real verbs instead. Use
|
|
54
|
-
`mm-harness call unlock` (fuzzy short-name resolution to `metamask.wallet.unlock`
|
|
55
|
-
when unambiguous).
|
|
56
|
-
- **The overlay is per-checkout, git-ignored plumbing — humans never manage it.**
|
|
57
|
-
Daily verbs (`launch`, `run`) check for the overlay at startup and
|
|
58
|
-
auto-install it inline with a one-line notice on first run on that checkout.
|
|
59
|
-
`install` is the explicit form for CI, agents, and deterministic setup
|
|
60
|
-
(`--heal=off` on daily verbs disables the inline check and all healing).
|
|
61
|
-
- **Your checkout's settings live in `agentic-runtime.json` — `doctor --fix` creates
|
|
62
|
-
local identity/resources when absent and `doctor` explains them;
|
|
63
|
-
you never hunt for the file.** `doctor` prints every field (slotId, extensionId,
|
|
64
|
-
cdpPort, runtimeStart.*), its current value, its source (file / env var /
|
|
65
|
-
default), and exactly how to change it. Arthur's rule made concrete: no
|
|
66
|
-
knowledge lock-in about which file to edit.
|
|
67
|
-
- **Verbs are idempotent — they make reality match intent; the recovery command is
|
|
68
|
-
the normal command.** `launch` and `run` detect broken runtime state
|
|
69
|
-
(Metro dead, Chrome/CDP offline, stale tabs) and heal before proceeding (controlled
|
|
70
|
-
by `--heal`; default `auto` for `launch`, `infra-only` for `run`). The
|
|
71
|
-
agent does not need a separate recovery verb: re-running `mm-harness launch ios`
|
|
72
|
-
IS the recovery. `--json` reports what was healed in a `recovered:[...]` field
|
|
73
|
-
(stable codes). `recoverable:false` + `attemptedRecoveries[]` stop agent retry
|
|
74
|
-
loops when bounds are hit. `doctor --fix` repairs without launching when healing
|
|
75
|
-
alone is the goal.
|
|
76
|
-
|
|
77
|
-
## Status legend
|
|
78
|
-
|
|
79
|
-
| Tag | Meaning |
|
|
80
|
-
|---|---|
|
|
81
|
-
| **ROUTES-NOW** | Works today through `mm-harness` (this draft) |
|
|
82
|
-
| **STUB** | `mm-harness` verb exists but exits 2 and teaches the working command; spec'd in Part 2 |
|
|
83
|
-
| **ABSORB-LATER** | Capability folds into an `mm-harness` verb (spec'd in Part 2 with a maps-to row) |
|
|
84
|
-
| **KEEP-INTERNAL** | Still reachable, just not a user-facing verb |
|
|
85
|
-
| **REMOVE** | Name/bin/subcommand deleted in the refactor wave; callers updated in the same wave (needs sign-off) |
|
|
86
|
-
|
|
87
|
-
## Bin & name table (before → after)
|
|
88
|
-
|
|
89
|
-
| Before | Role today | After |
|
|
90
|
-
|---|---|---|
|
|
91
|
-
| `bin/metamask-recipe` | public typed CLI + platform passthrough | **REMOVE** — becomes `bin/mm-harness` (same entrypoint, one name); no alias kept |
|
|
92
|
-
| `metamask-recipe harness <verb>` | overlay lifecycle subcommand | **REMOVE** — verbs live top-level (`mm-harness install/verify/cleanup`); `live` dissolved into `launch --verify` |
|
|
93
|
-
| `bin/mm-recipe` | mobile porcelain (Metro/sim/bridge) | **REMOVE** — capabilities become `mm-harness` verbs (Part 2); impl kept internal |
|
|
94
|
-
| `bin/mme-recipe` | extension porcelain (Chrome/CDP) | **REMOVE** — capabilities become `mm-harness` verbs (Part 2); impl kept internal |
|
|
95
|
-
| `recipe-harness` skill (~812 lines bash) | overlay lifecycle | **REMOVE** — thins to a caller of `mm-harness` overlay verbs |
|
|
96
|
-
| `completions/_recipe` (zsh; completes `recipe mme-recipe mm-recipe`) | shell completion | **REMOVE** — replaced by bundled `mm-harness` completions (zsh + bash), auto-installed on setup |
|
|
97
|
-
|
|
98
|
-
**`bin/mm-harness`** is the one user bin. **No per-platform binaries** —
|
|
99
|
-
`mm-mobile-harness` / `mm-extension-harness` are rejected (recreates the
|
|
100
|
-
three-names problem). Platform = auto-detected context; the positional target
|
|
101
|
-
forces it; platform-specific needs are FLAGS on the same verb.
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## BEFORE → AFTER by main command
|
|
106
|
-
|
|
107
|
-
Columns: **Human form** (bare verb / positional target; zero env prefixes;
|
|
108
|
-
defaults stated) · **Agent / advanced form** (explicit flags, `--json`) · **Status**.
|
|
109
|
-
|
|
110
|
-
### DAILY LOOP
|
|
111
|
-
|
|
112
|
-
#### `launch` — start the app (Metro/build + boot) · REAL (wave 3)
|
|
113
|
-
|
|
114
|
-
Auto-ensures runtime overlay before launching (installs inline with a one-line notice on first run; `--heal=off` to disable). **Idempotent + self-healing (default `--heal=auto`):** detects broken runtime state (Metro dead, Chrome/CDP offline, stale home tabs) and recovers before launching. The agent's recovery command is simply `mm-harness launch <target>` — no separate recovery verb. `--json` gains `"recovered": ["metro.restarted", ...]` (stable codes); `recoverable:false` + `attemptedRecoveries[]` stop retry loops. **`--verify`:** after launch, polls CDP/bridge until ready + runs smoke verify — implements the retired `live` sequence (zero capability lost). **Change detection:** quick launch (no `--build`) checks native/webpack build inputs; if changed → refuses with teaching error pointing at `--build`. Phase state-machine: `resolve → install → healthcheck → recover → launch → verify`.
|
|
115
|
-
|
|
116
|
-
| | |
|
|
117
|
-
|---|---|
|
|
118
|
-
| **Human form (mobile)** | `mm-harness launch ios` · `mm-harness launch android` — target **MANDATORY**; missing → teaching error: "specify ios or android" |
|
|
119
|
-
| **Human form (extension)** | `mm-harness launch` (no target; default `--fullscreen`; `--sidepanel` to open sidepanel mode) |
|
|
120
|
-
| **Quick vs full build** | bare `launch` = quick relaunch (no native/webpack build); `--build` = full build first |
|
|
121
|
-
| **Runway (mobile only)** | `--runway` runs a post-launch runway check; teaching error on extension |
|
|
122
|
-
| **`live` replacement** | `mm-harness launch ios --verify` (install overlay → launch → poll → smoke verify — never seeds fixtures) |
|
|
123
|
-
| **Agent / advanced** | `mm-harness launch --platform ios --device <udid> --build --verify --heal=off --json` |
|
|
124
|
-
|
|
125
|
-
| Today (real) | → mm-harness | Status |
|
|
126
|
-
|---|---|---|
|
|
127
|
-
| `mm-recipe ios` · `android` · `start` | `launch ios\|android` (positional, mandatory) | ABSORB-LATER |
|
|
128
|
-
| `mm-recipe up` | `launch ios --build` | ABSORB-LATER · [DEFAULT-GAP] tier hidden behind `MOBILE_PREFLIGHT_MODE=…` [ENV-GAP] |
|
|
129
|
-
| `mm-recipe refresh` · `reload` · `relaunch` | `launch ios\|android` (quick) | ABSORB-LATER |
|
|
130
|
-
| `mme-recipe rebuild` · `reopen` · `browser` · `launch` · `reload` · `reset` | `launch` (quick, extension) | ABSORB-LATER |
|
|
131
|
-
| `mme-recipe up` | `launch --build` (extension) | ABSORB-LATER |
|
|
132
|
-
| `mme-recipe watch` **then** `rebuild` | `launch --watch` (extension) | ABSORB-LATER · [DEFAULT-GAP] two commands today |
|
|
133
|
-
| `mme-recipe build` · `refresh` · `refresh-once` | `launch` tiers (extension) | ABSORB-LATER |
|
|
134
|
-
| `mme-recipe sidepanel [cycle\|open]` | `launch --sidepanel` (extension) | ABSORB-LATER |
|
|
135
|
-
|
|
136
|
-
#### `logs` — tail Metro/webpack + app logs · REAL (wave 3)
|
|
137
|
-
|
|
138
|
-
| | |
|
|
139
|
-
|---|---|
|
|
140
|
-
| **Human form** | `mm-harness logs` (compact, auto platform) |
|
|
141
|
-
| **Agent / advanced** | `mm-harness logs --full --platform mobile --json` |
|
|
142
|
-
|
|
143
|
-
| Today (real) | → mm-harness | Status |
|
|
144
|
-
|---|---|---|
|
|
145
|
-
| `mm-recipe logs` · `tail` · `logs --full` | `logs [--full]` | ABSORB-LATER · [ENV-GAP] `RECIPE_LOG_UI`/`RECIPE_LOG_EVENTS` → flags |
|
|
146
|
-
| `mme-recipe logs` · `tail` · `tail-webpack` | `logs` | ABSORB-LATER |
|
|
147
|
-
|
|
148
|
-
#### `debug` — open the debug console · REAL (wave 3)
|
|
149
|
-
|
|
150
|
-
| | |
|
|
151
|
-
|---|---|
|
|
152
|
-
| **Human form** | `mm-harness debug` (auto platform) |
|
|
153
|
-
| **Agent / advanced** | `mm-harness debug --worker` (extension SW) · `--dev-menu` · `--platform mobile` |
|
|
154
|
-
|
|
155
|
-
| Today (real) | → mm-harness | Status |
|
|
156
|
-
|---|---|---|
|
|
157
|
-
| `mme-recipe debug` · `devtools` · `inspect` · `debug worker` | `debug [--worker]` | ABSORB-LATER |
|
|
158
|
-
| `mm-recipe debug` | `debug` | ABSORB-LATER |
|
|
159
|
-
| `mm-recipe dev-menu` · `devmenu` | `debug --dev-menu` (flag) | ABSORB-LATER · [DEFAULT-GAP] separate verb for one console concept |
|
|
160
|
-
|
|
161
|
-
#### `fixtures` — initialize/sync fixture files + set up the wallet · REAL (wave 3)
|
|
162
|
-
|
|
163
|
-
One canonical wallet fixture per checkout (SSOT). Fixture status is reported by `doctor` automatically. Initialize from an existing secure team/test fixture or explicitly choose a disposable public dev wallet; secrets are never typed into chat or command arguments.
|
|
164
|
-
|
|
165
|
-
Subcommands: `fixtures init`, `fixtures sync`, `fixtures set`, plus Extension generate/finalize helpers.
|
|
166
|
-
|
|
167
|
-
| | |
|
|
168
|
-
|---|---|
|
|
169
|
-
| **Human form** | `mm-harness fixtures init --from <path>` or explicit `--dev` · `fixtures sync` · `fixtures set` (password read FROM the fixture, never typed) |
|
|
170
|
-
| **Agent / advanced** | `mm-harness fixtures set --fixture <json> --platform mobile` (`--fixture` is agent-only; humans edit the canonical file directly) |
|
|
171
|
-
|
|
172
|
-
| Today (real) | → mm-harness | Status |
|
|
173
|
-
|---|---|---|
|
|
174
|
-
| `mm-recipe sync` · `mme-recipe sync` | `fixtures sync` | ABSORB-LATER |
|
|
175
|
-
| `mme-recipe update` · `sync-runtime` | `fixtures sync` | ABSORB-LATER |
|
|
176
|
-
| `mm-recipe setup-wallet` · `wallet-setup` | `fixtures set` | ABSORB-LATER · [ENV-GAP] `RECIPE_WALLET_FIXTURE` → `--fixture` (agent-only) |
|
|
177
|
-
| `mm-recipe setup:ios` · `setup:android` | `launch ios` **then** `fixtures set` | ABSORB-LATER |
|
|
178
|
-
| `mm-recipe unlock` | `fixtures set` (password from fixture) | ABSORB-LATER · [ENV-GAP] `MM_PASSWORD=… unlock` is the anti-pattern — read the fixture |
|
|
179
|
-
| Extension standalone wallet setup | `fixtures set` | **[GAP]** no standalone verb today — the first-run wallet is seeded by the legacy `mme-recipe up`; end-state home is `fixtures set` (launch / `launch --verify` never seed) |
|
|
180
|
-
|
|
181
|
-
### DISCOVER (agent composition layer — `--json` is PRIMARY)
|
|
182
|
-
|
|
183
|
-
The composition loop: `actions --json` → `call <action>` (try one via real engine path) → `flows --json` → compose `recipe.json` → `run --plan` (adapter-aware validate + plan, no device) → `run`.
|
|
184
|
-
|
|
185
|
-
`manifest` is **RETIRED**: raw protocol dump → `actions --raw`; validation → `run --plan` / `doctor`. `validate` verb **DISSOLVED** into `run` (`run` validates first; `run --plan` = plan-only; same or richer shape, plus adapter cross-check). **DISCOVER final shape: `actions` · `call` · `flows`** — no manifest verb, no validate verb. Shell completions are sourced from this same layer: `call` completes action names, `run`/`run --plan` complete flow refs, both with a per-checkout short-TTL cache.
|
|
186
|
-
|
|
187
|
-
#### `actions` · `call` · `flows` · ROUTES-NOW (call: REAL wave 2)
|
|
188
|
-
|
|
189
|
-
| | |
|
|
190
|
-
|---|---|
|
|
191
|
-
| **Human form** | `mm-harness actions --adapter mobile` · `mm-harness call unlock` · `mm-harness flows` |
|
|
192
|
-
| **Agent PRIMARY** | `mm-harness actions --adapter mobile --json` → `{ adapter, actions: [{ name, kind, description, fields, examples }] }` |
|
|
193
|
-
| | `mm-harness call metamask.perps.read_positions --arg symbol=BTC --adapter core --json` → `{ action, resolvedAction, args, trace, evidence, recovered, mutations, exitCode, schemaVersion }` (same shape as `run --json`, one-node subset) |
|
|
194
|
-
| | `mm-harness flows --json` → `{ sources, flows: [{ ref, source, file, description?, requiredParams?, shadows?, lastVerified? }] }` |
|
|
195
|
-
| **Plan before run** | `mm-harness run recipe.json --plan --json` → `{ plan[], validation: { status, findings }, schemaVersion }` (adapter-aware; exit 5 on errors) |
|
|
196
|
-
|
|
197
|
-
| Today (real) | → mm-harness | Status |
|
|
198
|
-
|---|---|---|
|
|
199
|
-
| `metamask-recipe actions --adapter …` | `mm-harness actions --adapter …` | ROUTES-NOW · [DEFAULT-GAP] `--adapter` required · [DISCOVERY-GAP] no `--action <name>` filter, no `--kind` filter, no keyword search |
|
|
200
|
-
| `metamask-recipe flows list\|promote` | `mm-harness flows [\|promote]` | ROUTES-NOW · `flows` = browse the reusable flow library (compose, don't rewrite); `promote` publishes a proven flow up a tier · bare `flows` = list · [DISCOVERY-GAP] no keyword filter, no per-flow body fetch, no platform filter |
|
|
201
|
-
| `mm-recipe`/`mme-recipe` `actions`/`doctor` (auto adapter) | same `mm-harness` verbs | ABSORB-LATER — porcelain supplies missing adapter default |
|
|
202
|
-
| hook layer `run-action app.unlock` | `mm-harness call unlock` (fuzzy: `unlock` → `metamask.wallet.unlock`) — **one-node recipe via real engine path** | REAL (wave 2) · ambiguous → exit 2 listing candidates |
|
|
203
|
-
| `mm-harness validate recipe.json` (old stub) | `mm-harness run recipe.json --plan` | **DISSOLVED** — stub teaching message updated to point at `run --plan`; `validate-command.ts` called internally by run engine (phase: `validate`) |
|
|
204
|
-
|
|
205
|
-
### PROVE
|
|
206
|
-
|
|
207
|
-
#### `run` — validate + execute a recipe, write evidence · ROUTES-NOW
|
|
208
|
-
|
|
209
|
-
**Validates first (adapter-aware):** before touching any device, `run` checks action existence, platform support, and fixture preconditions. Exit 5 on validation errors (same code for `run`, `run --plan`, `call`). `--plan` = plan-only: prints what would happen, touches NO device, exits 0/5. Phase state-machine: `resolve → install → healthcheck → recover → validate → launch → execute`. `--heal` defaults `infra-only`; healing never touches wallet state — only the explicit `fixtures set` mutates it.
|
|
210
|
-
|
|
211
|
-
| | |
|
|
212
|
-
|---|---|
|
|
213
|
-
| **Human form** | `mm-harness run recipe.json` (adapter + artifacts auto-defaulted) |
|
|
214
|
-
| **Plan before run** | `mm-harness run recipe.json --plan` (adapter-aware; no device; exit 0 = valid, exit 5 = errors) |
|
|
215
|
-
| **Agent / advanced** | `mm-harness run recipe.json --adapter mobile --project-root <repo> --artifacts-dir <dir> --record-video=full-run --heal=off --json --json-stream` |
|
|
216
|
-
|
|
217
|
-
| Today (real) | → mm-harness | Status |
|
|
218
|
-
|---|---|---|
|
|
219
|
-
| `metamask-recipe run … --adapter … --artifacts-dir …` | `mm-harness run …` | ROUTES-NOW · [DEFAULT-GAP] `--adapter` + `--artifacts-dir` mandatory today · [ENV-GAP] `RECIPE_LIBRARY_PATH` → `--library`/config |
|
|
220
|
-
| `mm-recipe run recipe.json` · `mme-recipe run recipe.json` (auto adapter+artifacts) | `mm-harness run recipe.json` | ABSORB-LATER — porcelain already supplies the good defaults the typed CLI lacks |
|
|
221
|
-
|
|
222
|
-
#### `doctor` · ROUTES-NOW
|
|
223
|
-
|
|
224
|
-
Pure read-only diagnostic. Absorbs the retired `manifest` verb's validation: readiness checks include manifest well-formedness + reports manifest path + protocol version. `--fix` mode runs healing without launching (same path as `launch`/`verify` self-healing but stops short of starting the app).
|
|
225
|
-
|
|
226
|
-
| | |
|
|
227
|
-
|---|---|
|
|
228
|
-
| **Human form** | `mm-harness doctor` |
|
|
229
|
-
| **Agent / advanced** | `mm-harness doctor --adapter mobile --target <repo> --json` |
|
|
230
|
-
| **Repair without launch** | `mm-harness doctor --fix [--json]` → `{ ..., "fixed": [...], "failed": [...] }` |
|
|
231
|
-
|
|
232
|
-
| Today (real) | → mm-harness | Status |
|
|
233
|
-
|---|---|---|
|
|
234
|
-
| `metamask-recipe doctor --adapter … --target …` | `mm-harness doctor` | ROUTES-NOW · [DEFAULT-GAP] `--adapter`+`--target` required |
|
|
235
|
-
| `mm-recipe`/`mme-recipe` `doctor` (auto adapter/target) | `mm-harness doctor` | ABSORB-LATER — porcelain supplies the missing defaults |
|
|
236
|
-
|
|
237
|
-
### RUNTIME OVERLAY
|
|
238
|
-
|
|
239
|
-
#### `install` · `verify` · `cleanup` · ROUTES-NOW
|
|
240
|
-
|
|
241
|
-
`live` is **REMOVED** — dissolved into `launch --verify` (same sequence: install overlay if missing → launch → CDP poll → smoke verify; zero capability lost — `launch --verify` never seeds fixtures).
|
|
242
|
-
|
|
243
|
-
| | |
|
|
244
|
-
|---|---|
|
|
245
|
-
| **Human form** | `mm-harness install` · `verify` · `cleanup` (platform auto-detected, target = cwd) |
|
|
246
|
-
| **`live` replacement** | `mm-harness launch [ios\|android] --verify` |
|
|
247
|
-
| **Agent / advanced** | `mm-harness verify --platform extension --target <repo> --json -- --cdp-port <port>` |
|
|
248
|
-
|
|
249
|
-
| Today (real) | → mm-harness | Status |
|
|
250
|
-
|---|---|---|
|
|
251
|
-
| `recipe-harness install\|verify\|cleanup\|live …` (skill) | `mm-harness install\|verify\|cleanup` · `live` → `launch --verify` | ROUTES-NOW; skill REMOVE |
|
|
252
|
-
| `metamask-recipe harness install\|verify\|cleanup\|live …` | `mm-harness install\|verify\|cleanup` (top-level) · `live` → `launch --verify` | ROUTES-NOW; `harness` prefix REMOVE |
|
|
253
|
-
| `mm-recipe prepare` · `mme-recipe prepare` | `install` / `launch` prep | ABSORB-LATER |
|
|
254
|
-
| `mme-recipe ready` · `ensure-ready` | `verify` (or advanced `ensure-ready`) | ABSORB-LATER |
|
|
255
|
-
|
|
256
|
-
### ADVANCED (agent / internal — rarely typed by hand)
|
|
257
|
-
|
|
258
|
-
| Today (real) | → mm-harness | Status |
|
|
259
|
-
|---|---|---|
|
|
260
|
-
| `metamask-recipe runtime-health` · `runtime-decision` · `runtime-launch` · `resolve-extension` · `ensure-ready` · `self-test` | logic moves INSIDE `launch`/`verify` self-healing path — no user-facing verb; `self-test` callable via `package.json` scripts only | KEEP-INTERNAL |
|
|
261
|
-
| `metamask-recipe manifest --adapter …` | **RETIRED** — (1) validation → `doctor` readiness check; (2) raw dump → `mm-harness actions --raw`; (3) path + protocol version → `doctor` explain-my-setup | REMOVE |
|
|
262
|
-
| `mm-recipe`/`mme-recipe` `runtime-status` · `decision` · `ports` · `status\|home\|health` · `stop` | operator/infra flags on `mm-harness` (e.g. `--json` status) | ABSORB-LATER |
|
|
263
|
-
| `mm-recipe`/`mme-recipe` `completion\|complete` | bundled `mm-harness` completions (dynamic from DISCOVER layer) | KEEP-INTERNAL / REMOVE (old `_recipe`) |
|
|
264
|
-
| `mm-recipe`/`mme-recipe` `interactive\|menu` | interactive shell | ABSORB-LATER |
|
|
265
|
-
| `mm-recipe` bridge verbs: `app-status` · `route` · `navigate` · `back` · `accounts` · `select-account` · `screenshot` | recipe-driven or future flags | ABSORB-LATER |
|
|
266
|
-
|
|
267
|
-
---
|
|
268
|
-
|
|
269
|
-
## Decisions (final)
|
|
270
|
-
|
|
271
|
-
The surface below is settled — the design passed a three-round external review (final verdict: SOUND). The rulings that shape day-to-day use:
|
|
272
|
-
|
|
273
|
-
- **One bin, clean break.** `mm-harness` is the only command; `metamask-recipe` / `mm-recipe` / `mme-recipe` and the `harness <verb>` form are removed in the coordinated caller-sweep wave (CLI-SPEC.md Part 3).
|
|
274
|
-
- **DISCOVER = `actions · call · flows`.** `manifest` is retired (raw dump → `actions --raw`; validation → `run --plan` / `doctor`; path + protocol version → `doctor`). `validate` is dissolved into `run` (`run` always validates first; `run --plan` = plan-only, no device).
|
|
275
|
-
- **`call` is a one-node recipe** through the real engine path — same trace / evidence / `--json` shape as `run`; one execution path, two doors. `call` inherits `run` semantics in full (default `--heal=infra-only`).
|
|
276
|
-
- **`live` is dissolved into `launch --verify`** (install overlay → launch → CDP poll → smoke verify; zero capability lost — `launch --verify` never seeds fixtures). No `live` verb on any surface.
|
|
277
|
-
- **`--heal` = `off | infra-only | auto`** (+ `--yes` for non-interactive confirmation). `launch` defaults `auto`; `run` and `call` default `infra-only`; `off` is repro-preserving and also disables auto-install. Recovery bounds are ALWAYS enforced (recipe running / app-logic failure / same recovery already failed once → `recoverable:false`); no flag bypasses them. `--heal=off` is the single opt-out (it also disables auto-install).
|
|
278
|
-
- **Wallet state is mutated ONLY by the explicit `fixtures set`.** Healing never touches wallet state — overlay / Metro / Chrome recovery is infra; wallet data is not. If recovery would require a wallet write, the verb stops with `recoverable:false` and `userAction: "run mm-harness fixtures set"`. `fixtures` is wallet DATA only and never touches the overlay.
|
|
279
|
-
- **Overlay install notice** (not a "consent print"): stderr-only in human mode; in `--json` it appears solely as `mutations[]`, so stdout stays clean for machines.
|
|
280
|
-
- **Exit code 5 = validation failure everywhere** (`run`, `run --plan`, `call`) — no mode-specific meanings. `run --plan` items carry `confidence: static | conditional` so a plan never claims live runtime facts. Full taxonomy + agent error contract: CLI-SPEC.md Part 5.
|
|
281
|
-
- **Agent error contract:** structured `error:{code,message,cause,retryable,userAction}`, stable `recovered[]` / `mutations[]`, a phase state-machine, JSONL `--json-stream`, and `recoverable:false` + `attemptedRecoveries[]` to stop retry loops (CLI-SPEC.md Part 5).
|
|
282
|
-
- **Quick-launch change detection:** before a quick launch (no `--build`), `launch` checks native/webpack build inputs; if changed → teaching error pointing at `--build`. Never runs on a stale build.
|
|
283
|
-
- **Daily verbs auto-ensure the overlay**; humans never run `install`. `install` / `verify` / `cleanup` are the explicit top-level forms for CI/agents.
|
|
284
|
-
- **`flows` bare = list**; `flows promote` is the explicit subcommand.
|
|
285
|
-
- **Implementation:** `commander` (the library `@farmslot/recipe-harness` already uses) + bundled dynamic zsh/bash completions sourced from the DISCOVER layer.
|
|
286
|
-
|
|
287
|
-
**Deferred to later waves (sequencing, not open questions):** the `[DEFAULT-GAP]` auto-defaults (adapter/artifacts for `run` / `doctor` / `actions`), the `[ENV-GAP]` env→flag moves (CLI-SPEC.md Part 4), the caller sweep that deletes the old names (Part 3), and the repo rename.
|
|
288
|
-
|
|
289
|
-
### Considered and rejected
|
|
290
|
-
|
|
291
|
-
- **Teaching-tombstone stub bins** (`mm-harness-legacy`, etc.): Rejected. Pre-adoption burden with zero payoff; the coordinated wave (CLI-SPEC.md Part 3) updates all callers atomically. No tombstone bins needed.
|
|
292
|
-
|
|
293
|
-
## How farmslot calls mm-harness (preflight & the fleet binding)
|
|
294
|
-
|
|
295
|
-
"Preflight" survives as a capability, not an exposed concept: it is what `launch` does before returning (readiness: Metro/bundle → app → health/bridge poll), with `launch --verify` as the prove-it tier and `doctor` as the read-only view. The fleet is just another agent-grade caller — farmslot prepare profiles keep their git / fixtures / deps phases, and the preflight/health hooks collapse to one call: `mm-harness launch <target> --verify --heal=auto --json`. Same-capability by construction: the machine contract (`--json` schemas, `--heal`, exit-code taxonomy, `recovered[]` / `mutations[]` / `recoverable:false`) is the one agents already use. Three bindings, one verb: the engineer types `mm-harness launch ios`; the slot's prepare hook calls the same verb with slot context; dispatch scales it across the fleet. (Full contract: CLI-SPEC.md Part 6.)
|
package/docs/UX-PRINCIPLES.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# UX principles — the mm-harness interaction contract
|
|
2
|
-
|
|
3
|
-
Every command surface follows these rules. They are review criteria, not aspirations:
|
|
4
|
-
a PR that adds a command or output path is checked against each one.
|
|
5
|
-
|
|
6
|
-
**Scope: the HUMAN surface.** The agent contract is exempt and inviolable: under
|
|
7
|
-
`--json`, stdout carries exactly one machine-readable envelope — no color, no
|
|
8
|
-
banners, no decorative lines, schema per CLI-SPEC.md. Progress/streaming exists
|
|
9
|
-
for agents too, but only ever on stderr. When a rule below conflicts with envelope
|
|
10
|
-
purity, the envelope wins.
|
|
11
|
-
|
|
12
|
-
## 1. Context-aware by default
|
|
13
|
-
The CLI answers relative to the checkout it is standing in.
|
|
14
|
-
- Adapter is auto-detected everywhere (`--adapter` overrides; a bare command never
|
|
15
|
-
fails on a value detection can supply).
|
|
16
|
-
- The slot context the orchestrator wrote into the checkout
|
|
17
|
-
(`<runtime_dir>/agentic-runtime.json`) is the authoritative source for device,
|
|
18
|
-
ports, and slot identity — naming formulas are last-resort fallbacks and never
|
|
19
|
-
hardcode pool prefixes (they go stale on rename).
|
|
20
|
-
- Output is scoped to the platform: an extension-only field is noise on a mobile
|
|
21
|
-
slot; help, flag lists, and completion candidates shrink to what applies here.
|
|
22
|
-
- Enforcement: platform-specific behavior is resolved through the adapter surface
|
|
23
|
-
(`getAdapterSurface(adapter)`), never a per-command `if (adapter === …)` ladder —
|
|
24
|
-
that ladder is how commands go platform-blind. See docs/ADAPTER-SURFACE.md.
|
|
25
|
-
|
|
26
|
-
## 2. Never silent, never opaque
|
|
27
|
-
Long operations show intent immediately and progress continuously.
|
|
28
|
-
- First line within milliseconds: what is being done, where (device/port), and
|
|
29
|
-
where the full log lives.
|
|
30
|
-
- Leaf output streams live to stderr — `--json` reserves stdout for the envelope,
|
|
31
|
-
it never buys silence. Quiet stretches get heartbeats with elapsed time.
|
|
32
|
-
- Each dev server a command starts gets its tmux log-tail window at launch time
|
|
33
|
-
(window creation is launch-coupled; users re-create separately when they close one).
|
|
34
|
-
|
|
35
|
-
## 3. Summaries state outcomes
|
|
36
|
-
The final line says what actually happened: target device, what the tier meant,
|
|
37
|
-
resulting state — never a bare status word. Dev-override runs are marked
|
|
38
|
-
(`[dev: MM_HARNESS_BIN]`) so it is always evident which bin served.
|
|
39
|
-
|
|
40
|
-
## 4. Dev and prod are explicit
|
|
41
|
-
The global install is prod (`mm-harness`); a dev checkout runs via the documented
|
|
42
|
-
`MM_HARNESS_BIN` switch (conventionally aliased `mmdev-harness`). The dev override
|
|
43
|
-
announces itself in help and summaries. Completions cover both names.
|
|
44
|
-
|
|
45
|
-
## 5. Errors teach the exact escape
|
|
46
|
-
Every failure states the next command for the caller's actual situation. A wrong
|
|
47
|
-
hint (an escape for a different failure mode) is a bug of the same severity as
|
|
48
|
-
the failure itself.
|
|
49
|
-
|
|
50
|
-
## 6. Lifecycle verbs are symmetric and idempotent
|
|
51
|
-
What a command starts, a sibling verb stops (`launch`/`stop`), scoped to what this
|
|
52
|
-
checkout owns (port-scoped, session-scoped) — never "whatever is running".
|
|
53
|
-
Nothing-to-do is success. Tests never leak into the operator's real tmux.
|
|
54
|
-
|
|
55
|
-
## 7. Color is consistent and optional
|
|
56
|
-
All human output styles through `cli-color.ts` (headers, ok/warn/err states,
|
|
57
|
-
provenance, "Next:" hints); `NO_COLOR`/non-TTY degrade to plain text. No surface
|
|
58
|
-
invents its own ANSI.
|
|
59
|
-
|
|
60
|
-
## 8. Doctor is the status surface
|
|
61
|
-
`doctor` reports, per platform: live runtime state (deps currency, dev-server
|
|
62
|
-
up/stale on the slot's resolved port, app/browser presence), the scoped runtime
|
|
63
|
-
context with provenance (`[file]`/`[env]`/`[default]`), and the exact customize
|
|
64
|
-
hint per row. Read-only unless `--fix`.
|