@deeeed/metamask-harness 0.15.2 → 0.17.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 +23 -0
- package/README.md +12 -1
- package/dist/cli-commands.js +1 -1
- package/dist/cli.js +2 -0
- package/dist/command-contract.js +441 -0
- package/dist/command-journal.js +225 -0
- package/dist/commands/call.js +40 -17
- package/dist/commands/check.js +9 -3
- package/dist/commands/device-target.js +27 -12
- package/dist/commands/doctor.js +19 -6
- package/dist/commands/fixtures.js +1 -1
- package/dist/commands/last.js +52 -0
- package/dist/commands/launch/index.js +156 -59
- package/dist/commands/manifest.js +147 -9
- package/dist/commands/parse-args.js +2 -0
- package/dist/commands/provision.js +10 -3
- package/dist/commands/run-engine.js +34 -11
- package/dist/commands/run-report.js +12 -3
- package/dist/commands/run.js +194 -39
- package/dist/commands/shared.js +11 -1
- package/dist/commands/status.js +1 -1
- package/dist/commands/stop.js +7 -2
- package/dist/harness.js +16 -4
- package/dist/json-stream.js +57 -0
- package/dist/mm-harness-cli.js +114 -3
- package/dist/run-diagnostics.js +271 -0
- package/dist/runner.js +32 -1
- package/docs/CLI-ERGONOMICS-AUDIT.md +32 -0
- package/docs/CLI-ERGONOMICS-HUMAN-QA.md +104 -0
- package/docs/CLI-SPEC.md +63 -19
- package/docs/MENTAL-MODEL.md +2 -2
- package/docs/UX-PRINCIPLES.md +2 -0
- package/package.json +2 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!-- Generated by scripts/generate-cli-ergonomics-audit.mjs. Do not edit by hand. -->
|
|
2
|
+
# CLI ergonomics audit
|
|
3
|
+
|
|
4
|
+
This matrix tracks the public command surface. “Covered” means the shared preflight contract and
|
|
5
|
+
`tests/contract/cli-teaching-errors.test.sh` exercise the behavior without dispatching runtime work.
|
|
6
|
+
Runtime recovery is claimed only where command-specific failures return a stable `userAction`.
|
|
7
|
+
Success hints are intentionally limited to lifecycle transitions with one truthful next command;
|
|
8
|
+
discovery, read-only, and terminal evidence commands do not invent one. ID prefix support is N/A
|
|
9
|
+
unless a command displays a shortened ID that another command accepts.
|
|
10
|
+
|
|
11
|
+
| Command | Bad flag | First feedback | `--json` recovery | Success next step | Displayed ID prefix |
|
|
12
|
+
|---|---|---|---|---|---|
|
|
13
|
+
| `status` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | structured `next` | N/A: command displays no shortened ID |
|
|
14
|
+
| `checklist` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage errors covered; no runtime recovery claim | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
15
|
+
| `actions` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
16
|
+
| `stop` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | launch `next` when the adapter has one unambiguous launch | N/A: command displays no shortened ID |
|
|
17
|
+
| `call` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
18
|
+
| `flows` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage errors covered; no runtime recovery claim | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
19
|
+
| `run` | covered: `CLI_UNKNOWN_OPTION` | TTY intent before slow work; machine output clean | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
20
|
+
| `last` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
21
|
+
| `doctor` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
22
|
+
| `check` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
23
|
+
| `recipe-quality` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
24
|
+
| `provision` | covered: `CLI_UNKNOWN_OPTION` | TTY intent before slow work; machine output clean | usage + runtime `error.code/message/userAction` | launch `next` after install | N/A: command displays no shortened ID |
|
|
25
|
+
| `install` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | verify `next` | N/A: command displays no shortened ID |
|
|
26
|
+
| `verify` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | status `next` | N/A: command displays no shortened ID |
|
|
27
|
+
| `cleanup` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | install `next` | N/A: command displays no shortened ID |
|
|
28
|
+
| `launch` | covered: `CLI_UNKNOWN_OPTION` | TTY intent before slow work; machine output clean | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
29
|
+
| `logs` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
30
|
+
| `debug` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage errors covered; no runtime recovery claim | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
31
|
+
| `update` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
32
|
+
| `fixtures` | covered: `CLI_UNKNOWN_OPTION` | N/A: no newly introduced slow path | usage + runtime `error.code/message/userAction` | N/A: discovery, read-only, or terminal result | N/A: command displays no shortened ID |
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# CLI ergonomics human QA
|
|
2
|
+
|
|
3
|
+
Use this short pass after installing a release candidate. Automated contracts remain the release gate; this checklist confirms the experience in a real shell and checkout.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
export TARGET=/absolute/path/to/a/metamask-checkout
|
|
9
|
+
export ADAPTER=extension # extension, mobile, or core
|
|
10
|
+
mm-harness --version
|
|
11
|
+
mm-harness doctor --adapter "$ADAPTER" --target "$TARGET" --json | jq .status
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Expected: the intended version is printed and `doctor` returns parseable JSON. Resolve required doctor failures before continuing.
|
|
15
|
+
|
|
16
|
+
## 1. Teaching errors
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
out="$(mm-harness actions --categoriez --adapter "$ADAPTER" --json 2>/dev/null || true)"
|
|
20
|
+
jq '.error | {code, message, userAction}' <<<"$out"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Expected: `code` is stable, the message names the bad flag and valid options, and `userAction` suggests the closest valid invocation.
|
|
24
|
+
|
|
25
|
+
## 2. In-tool discovery
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
mm-harness actions --adapter "$ADAPTER" --categories
|
|
29
|
+
mm-harness actions status --adapter "$ADAPTER"
|
|
30
|
+
mm-harness actions --action app.status --adapter "$ADAPTER" --json | jq '{actions, relatedActions}'
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Expected: category output is compact, fuzzy search is bounded, and action detail includes related actions when available. A missing example action should produce a teaching error, not silent output.
|
|
34
|
+
|
|
35
|
+
## 3. Machine-output cleanliness and recovery
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
out="$(mm-harness call definitely.not.an.action --adapter "$ADAPTER" --target "$TARGET" --json 2>/dev/null || true)"
|
|
39
|
+
jq '{status, error}' <<<"$out"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Expected: stdout is one parseable JSON document with `error.code`, `error.message`, and `error.userAction`; it contains no spinner, banner, or human-only glyph.
|
|
43
|
+
|
|
44
|
+
## 4. Immediate human feedback
|
|
45
|
+
|
|
46
|
+
Run the platform-appropriate launch in an interactive terminal:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Extension
|
|
50
|
+
mm-harness launch --adapter extension --target "$TARGET"
|
|
51
|
+
|
|
52
|
+
# Mobile: choose the intended platform
|
|
53
|
+
mm-harness launch ios --target "$TARGET"
|
|
54
|
+
# mm-harness launch android --target "$TARGET"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Expected: intent/progress appears immediately, long work continues to report progress, and the app becomes ready. Redirected or `--json` stdout stays decoration-free.
|
|
58
|
+
|
|
59
|
+
## 5. Lifecycle next step
|
|
60
|
+
|
|
61
|
+
For Extension:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
mm-harness stop --adapter extension --target "$TARGET" --json | jq '{status, next}'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Expected: `next` is a target-scoped launch command. Mobile `stop` intentionally omits `next` because Metro does not identify whether iOS or Android should be relaunched.
|
|
68
|
+
|
|
69
|
+
## 6. Resume after interruption
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
mm-harness last --target "$TARGET" --json | jq '.last | {command, args, verdict, evidencePaths, startedAt, finishedAt}'
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Expected: the last operation can be reconstructed without rerunning it, including its arguments, verdict, evidence paths, and timestamps.
|
|
76
|
+
|
|
77
|
+
## 7. Recipe proof smoke
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
mm-harness run --list --adapter "$ADAPTER" --json | jq '{actions: .actions[0:5], flows: .flows[0:5]}'
|
|
81
|
+
export RECIPE=replace-with-a-safe-recipe-name-or-path
|
|
82
|
+
export ARTIFACTS_DIR="$(mktemp -d)"
|
|
83
|
+
mm-harness run "$RECIPE" --plan --adapter "$ADAPTER" --target "$TARGET" --json | jq '{status, plan}'
|
|
84
|
+
mm-harness run "$RECIPE" --adapter "$ADAPTER" --target "$TARGET" --artifacts-dir "$ARTIFACTS_DIR"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Expected: the plan validates before execution; the final result identifies evidence paths and `mm-harness last --json` records the run.
|
|
88
|
+
|
|
89
|
+
Optional JSONL check:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
mm-harness run "$RECIPE" --adapter "$ADAPTER" --target "$TARGET" --artifacts-dir "$ARTIFACTS_DIR-stream" --json-stream | jq -c .
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Expected: complete JSON objects arrive line by line while the run is active.
|
|
96
|
+
|
|
97
|
+
## Cleanup
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
[ "$ADAPTER" = core ] || mm-harness stop --adapter "$ADAPTER" --target "$TARGET"
|
|
101
|
+
mm-harness status --target "$TARGET" --json | jq .
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Record the harness version, checkout SHA, adapter/platform, failed command, exit code, and JSON envelope for any discrepancy.
|
package/docs/CLI-SPEC.md
CHANGED
|
@@ -366,6 +366,8 @@ Installs the cached Runway iOS dev client onto a prepared mobile slot. It does n
|
|
|
366
366
|
|
|
367
367
|
**Validates first (adapter-aware):** Before touching any device, `run` validates the recipe: action existence in the adapter's manifest, platform support for each action, and fixture preconditions. Validation errors exit 5 with a structured error list. `--plan` stops here — prints the plan and exits, no device touched. Without `--plan`, validation failures are fatal before any execution begins.
|
|
368
368
|
|
|
369
|
+
**Run-scoped diagnostics:** Mobile combines its bounded in-app issue buffer with application-log bytes appended while the recipe executes; Extension owns a CDP console subscription for the run. The bounded, redacted result is written to `diagnostics.json`, indexed as a diagnostic artifact, and summarized as non-blocking `sideFindings`; it never changes recipe pass/fail and does not claim causality. Core is headless, so this is N/A.
|
|
370
|
+
|
|
369
371
|
> **Wave-2 status:** adapter-aware validation (`validateRecipeDocument` +
|
|
370
372
|
> `validateRecipeWithManifest`, shared helper `validateRecipeAdapterAware`) is
|
|
371
373
|
> wired for **`run --plan`** and **`call`** at the pinned deps (`@farmslot/protocol`
|
|
@@ -377,7 +379,7 @@ Installs the cached Runway iOS dev client onto a prepared mobile slot. It does n
|
|
|
377
379
|
> recipe) validate fully; the execute path relies on the engine's own manifest
|
|
378
380
|
> validation. Tagged in code (`runner/src/cli.ts` `validateRecipeAdapterAware`).
|
|
379
381
|
|
|
380
|
-
**
|
|
382
|
+
**Execution phases:** `resolve → validate → install → healthcheck → execute`, with `recover` emitted only when bounded recovery actually runs. `--json-stream` emits each transition as it occurs.
|
|
381
383
|
|
|
382
384
|
**Auto-ensure overlay:** `run` checks for the runtime overlay before executing (phase: `install`). If missing: installs it inline with a one-line notice, then proceeds. **First-install overlay notice:** on the very first install for this checkout, prints `installed mm-harness overlay v<version> → <path>` to stderr in human mode; in `--json` it appears solely as `mutations[]`. Use `--heal=off` to disable all auto-install and healing.
|
|
383
385
|
|
|
@@ -387,6 +389,14 @@ Installs the cached Runway iOS dev client onto a prepared mobile slot. It does n
|
|
|
387
389
|
**Outputs:** `summary.json`, `trace.json`, `artifact-manifest.json`, screenshots/logs under `--artifacts-dir`.
|
|
388
390
|
**Maps-to:** A:`run` (ROUTES-NOW); C/D:`run` (ABSORB-LATER — supply the auto adapter+artifacts defaults the typed CLI lacks).
|
|
389
391
|
|
|
392
|
+
## `last` (resumability inspect verb)
|
|
393
|
+
|
|
394
|
+
**Synopsis:** `mm-harness last [--target <checkout>] [--runtime-dir <dir>] [--json]`
|
|
395
|
+
|
|
396
|
+
Reads `last-command.json`, the atomic per-checkout journal written before and after significant runtime/proof commands. The record contains redacted args, `running|pass|fail` verdict, exit code, explicit evidence/output paths, and start/finish timestamps. A process killed between writes remains `running`, allowing an agent to inspect rather than repeat side effects. Read-only discovery commands do not replace the record, and `last` never journals itself.
|
|
397
|
+
|
|
398
|
+
The file is mode `0600`; password, credential, auth, mnemonic, private-key, seed/SRP, secret, and token values are redacted before the first write. `--json` returns `{ command:"last", target, journalPath, status, exitCode, last }`. Missing or invalid state returns `LAST_NOT_FOUND` with an exact `userAction`.
|
|
399
|
+
|
|
390
400
|
## `doctor` (ROUTES-NOW → PROVE inspect verb)
|
|
391
401
|
|
|
392
402
|
Readiness check for a checkout without launching the app. Doctor is the single place to understand the full slot context — **no hunting for files**. It also absorbs the retired `manifest` verb's validation function: the readiness checks include manifest well-formedness (schema valid, no unknown action references) and report the manifest path + protocol version in the explain-my-setup section. It includes three grounded sub-sections:
|
|
@@ -559,9 +569,9 @@ pretty-printed fallback. `manifest` is **RETIRED**: raw protocol dump rehomes to
|
|
|
559
569
|
|
|
560
570
|
### `actions` (ROUTES-NOW → DISCOVER verb)
|
|
561
571
|
|
|
562
|
-
**Synopsis:** `mm-harness actions --adapter <p> [--json] [--
|
|
572
|
+
**Synopsis:** `mm-harness actions [query] --adapter <p> [--json] [--categories | --category <name> | --action <name>]`
|
|
563
573
|
|
|
564
|
-
**PRIMARY (agent):** `mm-harness actions --adapter mobile --json`
|
|
574
|
+
**PRIMARY (agent):** search from the task vocabulary, for example `mm-harness actions positions --adapter mobile --json`, then request one full `--action` schema. Use `--categories` only when the task does not provide a useful search term.
|
|
565
575
|
|
|
566
576
|
**`--json` output shape** (grounded — `actions --adapter core --json` confirmed):
|
|
567
577
|
```json
|
|
@@ -571,6 +581,7 @@ pretty-printed fallback. `manifest` is **RETIRED**: raw protocol dump rehomes to
|
|
|
571
581
|
{
|
|
572
582
|
"name": "metamask.perps.read_positions",
|
|
573
583
|
"kind": "custom",
|
|
584
|
+
"category": "perps",
|
|
574
585
|
"description": "Read live Perps positions...",
|
|
575
586
|
"fields": ["account", "action", "market", "markets", "mode", "selector", "side", "symbol", "symbols", "timeout_ms"],
|
|
576
587
|
"examples": [{ "node": { "action": "metamask.perps.read_positions", "account": "...", "symbol": "BTC" } }]
|
|
@@ -578,7 +589,7 @@ pretty-printed fallback. `manifest` is **RETIRED**: raw protocol dump rehomes to
|
|
|
578
589
|
]
|
|
579
590
|
}
|
|
580
591
|
```
|
|
581
|
-
`kind` is `"official"` (engine built-ins) or `"custom"` (MetaMask adapter actions). `fields` lists every accepted parameter name. `examples[].node` is a copy-pasteable recipe node.
|
|
592
|
+
`kind` is `"official"` (engine built-ins) or `"custom"` (MetaMask adapter actions). `category` uses manifest metadata when present, then stable generic groups for protocol primitives and durable action namespaces (`ui.*` → `ui`, `metamask.perps.*` → `perps`). `fields` lists every accepted parameter name. `examples[].node` is a copy-pasteable recipe node.
|
|
582
593
|
|
|
583
594
|
**Human form:** `mm-harness actions --adapter mobile` — one line per action: `<name> (<kind>) <description> fields=<f1,f2,...>`.
|
|
584
595
|
|
|
@@ -586,12 +597,13 @@ pretty-printed fallback. `manifest` is **RETIRED**: raw protocol dump rehomes to
|
|
|
586
597
|
|---|---|---|---|---|---|
|
|
587
598
|
| `--adapter <p>` | mobile\|extension\|core | auto-detect | `RECIPE_HARNESS_PLATFORM` | both | Target adapter · [DEFAULT-GAP] required today |
|
|
588
599
|
| `--action <name>` | string | all | — | agent | Filter to one action; full schema + all examples |
|
|
589
|
-
| `--
|
|
600
|
+
| `--categories` | bool | false | — | agent | Return only sorted category names and action counts |
|
|
601
|
+
| `--category <name>` | string | all | — | agent | Return actions from one namespace-derived category |
|
|
590
602
|
| `--action-manifest <path>` | path | bundled | — | agent | Override manifest |
|
|
591
603
|
| `--raw` | bool | false | — | agent | Dump the underlying action manifest JSON (protocol version, registry version, all entries in raw registry format — same output as `manifest --json` today; replaces the retired `manifest` verb) |
|
|
592
604
|
| `--json` | bool | false | — | **agent PRIMARY** | Full schema + fields + examples per action |
|
|
593
605
|
|
|
594
|
-
|
|
606
|
+
The optional positional `query` searches names, categories, fields, and descriptions with typo tolerance. A single `--action` detail also returns up to five compact `relatedActions` names. Flow discovery remains separate.
|
|
595
607
|
**Exit:** 0 / non-zero on engine error.
|
|
596
608
|
**Maps-to:** A:`actions` (ROUTES-NOW); C/D:`actions` (ABSORB-LATER).
|
|
597
609
|
|
|
@@ -897,6 +909,36 @@ Every failure in `--json` mode produces an `error` field at the top level:
|
|
|
897
909
|
| `retryable` | boolean | `true` = same command may succeed on retry; `false` = agent must change inputs or escalate |
|
|
898
910
|
| `userAction` | string \| null | Exact next command or manual step |
|
|
899
911
|
|
|
912
|
+
Successful lifecycle transitions may add a top-level `next` command when exactly
|
|
913
|
+
one follow-up is correct (for example install → verify or stop → relaunch).
|
|
914
|
+
Discovery, read-only, and terminal evidence commands intentionally omit it rather
|
|
915
|
+
than inventing guidance. Agents must therefore treat `next` as optional.
|
|
916
|
+
|
|
917
|
+
Public command-grammar failures happen before runtime dispatch and always exit 2.
|
|
918
|
+
Their machine envelope is deliberately smaller and stable: agents branch on
|
|
919
|
+
`error.code`, never on prose.
|
|
920
|
+
|
|
921
|
+
```json
|
|
922
|
+
{
|
|
923
|
+
"schemaVersion": 1,
|
|
924
|
+
"command": "actions",
|
|
925
|
+
"status": "fail",
|
|
926
|
+
"error": {
|
|
927
|
+
"code": "CLI_UNKNOWN_OPTION",
|
|
928
|
+
"message": "unknown option '--categoriez'. Valid options for mm-harness actions: ...",
|
|
929
|
+
"userAction": "Did you mean '--categories' instead of '--categoriez'? Try: mm-harness actions --adapter mobile"
|
|
930
|
+
},
|
|
931
|
+
"exitCode": 2
|
|
932
|
+
}
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
Stable grammar codes are `CLI_UNKNOWN_COMMAND`, `CLI_UNKNOWN_OPTION`,
|
|
936
|
+
`CLI_MISSING_OPTION_VALUE`, `CLI_INVALID_OPTION_VALUE`,
|
|
937
|
+
`CLI_MISSING_POSITIONAL`, `CLI_INVALID_POSITIONAL`,
|
|
938
|
+
`CLI_EXCESS_POSITIONAL`, and `CLI_UNEXPECTED_PASSTHROUGH`. Every public
|
|
939
|
+
command is tracked in `docs/CLI-ERGONOMICS-AUDIT.md`; private adapter leaves keep
|
|
940
|
+
their own grammar behind explicit `--` passthrough.
|
|
941
|
+
|
|
900
942
|
## §5.2 Stable recovery codes (`recovered[]`)
|
|
901
943
|
|
|
902
944
|
`recovered[]` in `--json` output lists what was healed. These are stable enum values — not prose, safe to match in agent code:
|
|
@@ -937,18 +979,20 @@ Every `--json` response includes `mutations[]` listing all side effects the comm
|
|
|
937
979
|
|
|
938
980
|
## §5.4 Phase state-machine
|
|
939
981
|
|
|
940
|
-
|
|
982
|
+
Summary `--json` responses retain their command-specific `phase` field. `--json-stream` emits transitions as they occur, so an agent can distinguish active work from a stalled command.
|
|
941
983
|
|
|
942
984
|
**`run` phases:**
|
|
943
985
|
```
|
|
944
|
-
resolve →
|
|
986
|
+
resolve → validate → install → healthcheck → execute
|
|
945
987
|
```
|
|
946
988
|
|
|
947
989
|
**`launch` phases:**
|
|
948
990
|
```
|
|
949
|
-
resolve → install → healthcheck →
|
|
991
|
+
resolve → install → healthcheck → launch → verify
|
|
950
992
|
```
|
|
951
993
|
|
|
994
|
+
`recover` is conditional and appears immediately before a bounded recovery attempt; `verify` appears only for `launch --verify`.
|
|
995
|
+
|
|
952
996
|
| Phase | What happens |
|
|
953
997
|
|---|---|
|
|
954
998
|
| `resolve` | Recipe/target/adapter resolved; library sources loaded |
|
|
@@ -962,20 +1006,20 @@ resolve → install → healthcheck → recover → launch → verify
|
|
|
962
1006
|
|
|
963
1007
|
## §5.5 JSONL event stream (`--json-stream`)
|
|
964
1008
|
|
|
965
|
-
`--json-stream
|
|
1009
|
+
`run` and `launch` accept `--json-stream`. Each progress event is written as one complete JSON object plus a newline, so a piped reader can parse it before the command finishes. Schema is versioned via `schemaVersion`; every event also carries `command` and `ts`.
|
|
1010
|
+
|
|
1011
|
+
Stream mode owns stdout: existing human or subprocess output is routed to stderr. If both `--json` and `--json-stream` are supplied, stream mode wins. The existing summary `--json` bytes are unchanged when stream mode is absent.
|
|
966
1012
|
|
|
967
1013
|
```jsonl
|
|
968
|
-
{"schemaVersion":1,"event":"phase","phase":"resolve","ts":"2026-07-02T10:00:00.000Z"}
|
|
969
|
-
{"schemaVersion":1,"event":"phase","phase":"
|
|
970
|
-
{"schemaVersion":1,"
|
|
971
|
-
{"schemaVersion":1,"event":"
|
|
972
|
-
{"schemaVersion":1,"event":"
|
|
973
|
-
{"schemaVersion":1,"event":"
|
|
974
|
-
{"schemaVersion":1,"event":"node","index":0,"action":"metamask.wallet.unlock","status":"passed","ts":"..."}
|
|
975
|
-
{"schemaVersion":1,"event":"complete","status":"pass","exitCode":0,"recovered":[],"mutations":[...],"ts":"..."}
|
|
1014
|
+
{"schemaVersion":1,"command":"run","event":"phase","phase":"resolve","ts":"2026-07-02T10:00:00.000Z"}
|
|
1015
|
+
{"schemaVersion":1,"command":"run","event":"phase","phase":"validate","ts":"2026-07-02T10:00:00.100Z"}
|
|
1016
|
+
{"schemaVersion":1,"command":"run","event":"phase","phase":"execute","ts":"..."}
|
|
1017
|
+
{"schemaVersion":1,"command":"run","event":"node","nodeId":"unlock","action":"metamask.wallet.unlock","status":"running","ts":"..."}
|
|
1018
|
+
{"schemaVersion":1,"command":"run","event":"node","nodeId":"unlock","action":"metamask.wallet.unlock","status":"passed","ts":"..."}
|
|
1019
|
+
{"schemaVersion":1,"command":"run","event":"complete","status":"pass","exitCode":0,"reportPath":"/.../report.md","artifactManifestPath":"/.../artifact-manifest.json","recovered":[],"mutations":[],"ts":"..."}
|
|
976
1020
|
```
|
|
977
1021
|
|
|
978
|
-
Event types: `phase` · `node` · `mutation` · `recovery` · `error` · `complete`.
|
|
1022
|
+
Event types: `phase` · `node` · `mutation` · `recovery` · `error` · `complete`. Node events use stable recipe `nodeId` values rather than an inferred numeric order. Exactly one terminal `complete` event is last on normal success or handled failure, giving agents a clean sentinel and compact evidence paths without repeating the full run result.
|
|
979
1023
|
|
|
980
1024
|
## §5.6 Exit code taxonomy
|
|
981
1025
|
|
package/docs/MENTAL-MODEL.md
CHANGED
|
@@ -189,14 +189,14 @@ The composition loop: `actions --json` → `call <action>` (try one via real eng
|
|
|
189
189
|
| | |
|
|
190
190
|
|---|---|
|
|
191
191
|
| **Human form** | `mm-harness actions --adapter mobile` · `mm-harness call unlock` · `mm-harness flows` |
|
|
192
|
-
| **Agent PRIMARY** | `mm-harness actions --adapter mobile --json
|
|
192
|
+
| **Agent PRIMARY** | `mm-harness actions <task-term> --adapter mobile --json`, then one focused `--action <name>` schema; use `--categories` only without a useful term |
|
|
193
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
194
|
| | `mm-harness flows --json` → `{ sources, flows: [{ ref, source, file, description?, requiredParams?, shadows?, lastVerified? }] }` |
|
|
195
195
|
| **Plan before run** | `mm-harness run recipe.json --plan --json` → `{ plan[], validation: { status, findings }, schemaVersion }` (adapter-aware; exit 5 on errors) |
|
|
196
196
|
|
|
197
197
|
| Today (real) | → mm-harness | Status |
|
|
198
198
|
|---|---|---|
|
|
199
|
-
| `metamask-recipe actions --adapter …` | `mm-harness actions --adapter …` | ROUTES-NOW ·
|
|
199
|
+
| `metamask-recipe actions --adapter …` | `mm-harness actions --adapter …` | ROUTES-NOW · auto-detects in a checkout · bounded category/action views shipped · [DISCOVERY-GAP] no keyword search |
|
|
200
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
201
|
| `mm-recipe`/`mme-recipe` `actions`/`doctor` (auto adapter) | same `mm-harness` verbs | ABSORB-LATER — porcelain supplies missing adapter default |
|
|
202
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 |
|
package/docs/UX-PRINCIPLES.md
CHANGED
|
@@ -27,6 +27,8 @@ The CLI answers relative to the checkout it is standing in.
|
|
|
27
27
|
Long operations show intent immediately and progress continuously.
|
|
28
28
|
- First line within milliseconds: what is being done, where (device/port), and
|
|
29
29
|
where the full log lives.
|
|
30
|
+
- Add an explicit first line only when work can block before existing output. Fast
|
|
31
|
+
commands use their result as acknowledgement; they do not print a redundant banner.
|
|
30
32
|
- Leaf output streams live to stderr — `--json` reserves stdout for the envelope,
|
|
31
33
|
it never buys silence. Quiet stretches get heartbeats with elapsed time.
|
|
32
34
|
- Each dev server a command starts gets its tmux log-tail window at launch time
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeeed/metamask-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mm-harness": "bin/mm-harness"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "node scripts/build-dist.mjs",
|
|
10
|
+
"audit:cli-ergonomics": "node scripts/generate-cli-ergonomics-audit.mjs",
|
|
10
11
|
"prepack": "npm run build",
|
|
11
12
|
"dev:link-farmslot": "node scripts/link-local-farmslot.mjs",
|
|
12
13
|
"check": "node scripts/check.mjs",
|