@deeeed/metamask-harness 0.17.2 → 0.17.3
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 +28 -8
- package/README.md +12 -6
- package/adapters/core/cleanup.sh +0 -0
- package/adapters/core/inject.sh +0 -0
- package/adapters/extension/cleanup.mjs +0 -0
- package/adapters/extension/ensure-browser.sh +0 -0
- package/adapters/extension/inject.mjs +0 -0
- package/adapters/extension/launch-browser.cjs +0 -0
- package/adapters/extension/launch.sh +0 -0
- package/adapters/extension/live.sh +0 -0
- package/adapters/extension/readiness.mjs +0 -0
- package/adapters/extension/reattach.sh +0 -0
- package/adapters/extension/refresh-build.sh +0 -0
- package/adapters/extension/seed-fixture.sh +0 -0
- package/adapters/extension/sidepanel-toggle.sh +0 -0
- package/adapters/extension/snapshot-dist.sh +0 -0
- package/adapters/extension/start-watch.sh +1 -0
- package/adapters/extension/stop-viewers.sh +0 -0
- package/adapters/extension/sync-webpack-dist.cjs +1 -1
- package/adapters/extension/verify.sh +0 -0
- package/adapters/extension/wallet-fixture-state.cjs +0 -0
- package/adapters/manifest.json +9 -1
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +0 -0
- package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +3 -1
- package/adapters/mobile/bridge-runtime/setup-wallet.sh +0 -0
- package/adapters/mobile/cleanup.sh +0 -0
- package/adapters/mobile/inject.sh +13 -11
- package/adapters/mobile/launch-console-forwarder.cjs +0 -0
- package/adapters/mobile/lib/metro-listener.sh +0 -0
- package/adapters/mobile/lib/tmux-viewer.sh +0 -0
- package/adapters/mobile/open-device.sh +0 -0
- package/adapters/mobile/prewarm-bundle.sh +0 -0
- package/adapters/mobile/start-console-forwarder.sh +3 -3
- package/adapters/mobile/start-metro.sh +0 -0
- package/adapters/mobile/stop-metro.sh +0 -0
- package/adapters/mobile/verify.sh +0 -0
- package/adapters/mobile/wait-for-bridge.sh +22 -8
- package/adapters/mobile/yarn-setup.sh +0 -0
- package/adapters/shared/activate-repo-node.sh +0 -0
- package/adapters/shared/activate-repo-ruby.sh +0 -0
- package/adapters/shared/cli-ux.sh +0 -0
- package/adapters/shared/ensure-runner-deps.sh +0 -0
- package/adapters/shared/harness-path.sh +0 -0
- package/adapters/shared/hash-helpers.sh +0 -0
- package/adapters/shared/install-repo-deps.sh +0 -0
- package/adapters/shared/json-field.sh +0 -0
- package/adapters/shared/open-debug.mjs +7 -1
- package/adapters/shared/open-log-window.sh +0 -0
- package/adapters/shared/reap-checkout-metros.sh +0 -0
- package/adapters/shared/resolve-slot-ports.mjs +0 -0
- package/adapters/shared/resolve-slot-ports.sh +0 -0
- package/adapters/shared/sync-wallet-fixture.sh +0 -0
- package/adapters/shared/tmux-session.sh +0 -0
- package/adapters/shared/tmux-viewer.sh +0 -0
- package/adapters/shared/update-check-worker.mjs +2 -4
- package/dist/adapters/extension/console-capture.js +10 -1
- package/dist/adapters/mobile/prepare.js +5 -5
- package/dist/adapters/slot-ports.js +8 -0
- package/dist/cli.js +1 -1
- package/dist/commands/doctor.js +33 -8
- package/dist/commands/run-engine.js +2 -4
- package/dist/commands/update.js +2 -1
- package/dist/harness.js +24 -9
- package/dist/mm-harness-cli.js +7 -6
- package/dist/run-diagnostics.js +1 -6
- package/docs/ADAPTER-SURFACE.md +19 -112
- package/docs/CLI-ERGONOMICS-HUMAN-QA.md +16 -0
- package/docs/UX-PRINCIPLES.md +1 -1
- package/docs/VIDEO-DEMO-VALIDATION.md +56 -44
- package/docs/recipe-libraries.md +45 -275
- package/library/README.md +4 -0
- package/library/manifests/core.action-manifest.json +7 -7
- package/library/recipes/runner/smoke.core.recipe.json +27 -0
- package/library/recipes/wallet/smoke.extension.recipe.json +42 -0
- package/library/recipes/wallet/smoke.mobile.recipe.json +42 -0
- package/package.json +4 -2
- package/scripts/completions.sh +0 -0
- package/scripts/install-completions.sh +0 -0
- package/scripts/validate-human-outcomes.mjs +169 -0
package/dist/harness.js
CHANGED
|
@@ -71,6 +71,7 @@ function parseHarnessArgs(args) {
|
|
|
71
71
|
const forward = [];
|
|
72
72
|
let adapter;
|
|
73
73
|
let json = false;
|
|
74
|
+
let quiet = false;
|
|
74
75
|
let separator = false;
|
|
75
76
|
for (let i = 0; i < args.length; i += 1) {
|
|
76
77
|
const arg = args[i];
|
|
@@ -86,6 +87,10 @@ function parseHarnessArgs(args) {
|
|
|
86
87
|
json = true;
|
|
87
88
|
continue;
|
|
88
89
|
}
|
|
90
|
+
if (arg === "--quiet") {
|
|
91
|
+
quiet = true;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
89
94
|
if (arg === "--adapter" || arg === "--platform") {
|
|
90
95
|
const value = args[i + 1];
|
|
91
96
|
if (arg === "--adapter") {
|
|
@@ -116,7 +121,7 @@ function parseHarnessArgs(args) {
|
|
|
116
121
|
}
|
|
117
122
|
forward.push(arg);
|
|
118
123
|
}
|
|
119
|
-
return { adapter, json, forward };
|
|
124
|
+
return { adapter, json, quiet, forward };
|
|
120
125
|
}
|
|
121
126
|
const ADAPTER_DETECT_NEXT = "cd into a MetaMask checkout or pass --target <path>, or force it with --adapter <mobile|extension|core>";
|
|
122
127
|
function detectAdapter(target) {
|
|
@@ -276,12 +281,14 @@ async function handleHarness(argv) {
|
|
|
276
281
|
return 2;
|
|
277
282
|
}
|
|
278
283
|
const harnessAction = action;
|
|
279
|
-
const { adapter: parsedAdapter, json, forward } = parseHarnessArgs(argv.slice(1));
|
|
284
|
+
const { adapter: parsedAdapter, json, quiet, forward } = parseHarnessArgs(argv.slice(1));
|
|
280
285
|
const rawTarget = argValue(forward, "--target");
|
|
281
286
|
const target = path.resolve(rawTarget ?? process.cwd());
|
|
282
287
|
const adapter = parsedAdapter ?? detectAdapter(target);
|
|
283
288
|
if (!adapter || !isAdapter(adapter)) {
|
|
284
|
-
if (
|
|
289
|
+
if (quiet) {
|
|
290
|
+
return 2;
|
|
291
|
+
} else if (json) {
|
|
285
292
|
const detectError = adapter ? { code: "UNSUPPORTED_PLATFORM", message: `unsupported platform: ${adapter}`, userAction: "pass --adapter <mobile|extension|core> to specify a supported adapter" } : { code: "ADAPTER_DETECTION_FAILED", message: `could not detect the MetaMask repo type for ${target}`, userAction: ADAPTER_DETECT_NEXT };
|
|
286
293
|
console.log(harnessSummary(harnessAction, void 0, target, "fail", 2, false, detectError));
|
|
287
294
|
} else {
|
|
@@ -305,7 +312,9 @@ async function handleHarness(argv) {
|
|
|
305
312
|
}
|
|
306
313
|
const dispatch = resolveHarnessDispatch(adapter, harnessAction, target);
|
|
307
314
|
if ("error" in dispatch) {
|
|
308
|
-
if (
|
|
315
|
+
if (quiet) {
|
|
316
|
+
return 1;
|
|
317
|
+
} else if (json) {
|
|
309
318
|
console.log(
|
|
310
319
|
harnessSummary(harnessAction, adapter, target, "fail", 1, autoDetected, {
|
|
311
320
|
code: "DISPATCH_UNAVAILABLE",
|
|
@@ -321,14 +330,16 @@ async function handleHarness(argv) {
|
|
|
321
330
|
}
|
|
322
331
|
return 1;
|
|
323
332
|
}
|
|
324
|
-
if (!json) {
|
|
333
|
+
if (!json && !quiet) {
|
|
325
334
|
const detected = autoDetected ? ", auto-detected" : "";
|
|
326
335
|
console.error(`\u2192 ${harnessAction} (${adapter}${detected}) \u2014 target: ${target}`);
|
|
327
336
|
}
|
|
328
337
|
const start = Date.now();
|
|
329
338
|
if (shellLeafMissing(dispatch.command)) {
|
|
330
339
|
const message = missingShellLeafMessage(dispatch.command);
|
|
331
|
-
if (
|
|
340
|
+
if (quiet) {
|
|
341
|
+
return 1;
|
|
342
|
+
} else if (json) {
|
|
332
343
|
console.log(
|
|
333
344
|
harnessSummary(harnessAction, adapter, target, "fail", 1, autoDetected, {
|
|
334
345
|
code: "HARNESS_SPAWN_FAILED",
|
|
@@ -348,12 +359,14 @@ async function handleHarness(argv) {
|
|
|
348
359
|
const result = spawnSync(dispatchBin, dispatchArgs, {
|
|
349
360
|
// Default: stream child output verbatim (byte-identical to the skill path).
|
|
350
361
|
// --json: route child output to our stderr so stdout carries only the summary.
|
|
351
|
-
stdio: json ? ["inherit", 2, "inherit"] : "inherit",
|
|
362
|
+
stdio: quiet ? "ignore" : json ? ["inherit", 2, "inherit"] : "inherit",
|
|
352
363
|
env: process.env
|
|
353
364
|
});
|
|
354
365
|
const seconds = ((Date.now() - start) / 1e3).toFixed(1);
|
|
355
366
|
if (result.error) {
|
|
356
|
-
if (
|
|
367
|
+
if (quiet) {
|
|
368
|
+
return 1;
|
|
369
|
+
} else if (json) {
|
|
357
370
|
console.log(
|
|
358
371
|
harnessSummary(harnessAction, adapter, target, "fail", 1, autoDetected, {
|
|
359
372
|
code: "HARNESS_SPAWN_FAILED",
|
|
@@ -368,7 +381,9 @@ async function handleHarness(argv) {
|
|
|
368
381
|
return 1;
|
|
369
382
|
}
|
|
370
383
|
const exitCode = result.status ?? 1;
|
|
371
|
-
if (
|
|
384
|
+
if (quiet) {
|
|
385
|
+
return exitCode;
|
|
386
|
+
} else if (json) {
|
|
372
387
|
console.log(
|
|
373
388
|
harnessSummary(
|
|
374
389
|
harnessAction,
|
package/dist/mm-harness-cli.js
CHANGED
|
@@ -76,11 +76,11 @@ Example:
|
|
|
76
76
|
},
|
|
77
77
|
{
|
|
78
78
|
name: "actions",
|
|
79
|
-
summary: "
|
|
79
|
+
summary: "Discover typed single operations and their fields.",
|
|
80
80
|
example: "mm-harness actions --adapter mobile",
|
|
81
81
|
helpText: `mm-harness actions [query] [flags]
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
Discover typed single operations and their field schemas for this checkout.
|
|
84
84
|
|
|
85
85
|
query Search names, categories, fields, and descriptions (typo-tolerant)
|
|
86
86
|
--action <name> Describe one action; fuzzy-resolves like call (short or full name)
|
|
@@ -152,11 +152,11 @@ Example (real actions; run mm-harness actions for this checkout's full set):
|
|
|
152
152
|
},
|
|
153
153
|
{
|
|
154
154
|
name: "flows",
|
|
155
|
-
summary: "Browse
|
|
155
|
+
summary: "Browse reusable parameterized action sequences.",
|
|
156
156
|
example: "mm-harness flows",
|
|
157
157
|
helpText: `mm-harness flows [flags]
|
|
158
158
|
|
|
159
|
-
Browse
|
|
159
|
+
Browse reusable parameterized action sequences. Flows resolve by precedence
|
|
160
160
|
(personal > team > canonical); the highest-tier copy wins and shadows lower ones.
|
|
161
161
|
Flow resolution is adapter-global, so there is no --adapter flag here.
|
|
162
162
|
|
|
@@ -169,11 +169,12 @@ Example:
|
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
name: "run",
|
|
172
|
-
summary: "
|
|
172
|
+
summary: "Execute a complete proof and write its evidence.",
|
|
173
173
|
example: "mm-harness run recipe.json",
|
|
174
174
|
helpText: `mm-harness run <recipe.json> [flags]
|
|
175
175
|
|
|
176
|
-
Validate
|
|
176
|
+
Validate and execute a complete proof, then write summary, trace, diagnostics,
|
|
177
|
+
and artifacts. A recipe may use actions directly or call reusable flows.
|
|
177
178
|
|
|
178
179
|
--list List everything invocable for the adapter (actions + flows); no <recipe> needed
|
|
179
180
|
--plan Validate + print execution plan, touching nothing. Exit 5 if invalid.
|
package/dist/run-diagnostics.js
CHANGED
|
@@ -52,7 +52,6 @@ function isRunDiagnosticsDocument(value) {
|
|
|
52
52
|
function finishRunDiagnostics(baseline, result) {
|
|
53
53
|
if (!baseline) return result;
|
|
54
54
|
try {
|
|
55
|
-
stopRunDiagnostics(baseline);
|
|
56
55
|
const bufferedIssues = baseline.mobileIssueBuffer ? collectMobileIssueBuffer(baseline.mobileIssueBuffer.projectRoot) : void 0;
|
|
57
56
|
const diagnostics = collectRunDiagnostics(baseline, bufferedIssues);
|
|
58
57
|
const artifactsDir = path.dirname(result.summaryPath);
|
|
@@ -83,9 +82,6 @@ function finishRunDiagnostics(baseline, result) {
|
|
|
83
82
|
};
|
|
84
83
|
}
|
|
85
84
|
}
|
|
86
|
-
function stopRunDiagnostics(baseline) {
|
|
87
|
-
void baseline;
|
|
88
|
-
}
|
|
89
85
|
function collectRunDiagnostics(baseline, bufferedIssues) {
|
|
90
86
|
const stat = safeStat(baseline.source.path);
|
|
91
87
|
const source = {
|
|
@@ -261,6 +257,5 @@ export {
|
|
|
261
257
|
collectRunDiagnostics,
|
|
262
258
|
finishRunDiagnostics,
|
|
263
259
|
formatRunDiagnosticsForHuman,
|
|
264
|
-
readRunDiagnosticsDocument
|
|
265
|
-
stopRunDiagnostics
|
|
260
|
+
readRunDiagnosticsDocument
|
|
266
261
|
};
|
package/docs/ADAPTER-SURFACE.md
CHANGED
|
@@ -1,119 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Adapter surface
|
|
2
2
|
|
|
3
|
-
`
|
|
4
|
-
|
|
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.
|
|
3
|
+
`src/adapters/surface.ts` is the typed seam for Mobile, Extension, and Core.
|
|
4
|
+
Commands ask it for platform behavior instead of re-deriving platform rules.
|
|
10
5
|
|
|
11
|
-
|
|
12
|
-
a registry, that owns the behavior a command would otherwise branch on.
|
|
6
|
+
Each adapter implements:
|
|
13
7
|
|
|
14
|
-
|
|
8
|
+
- runtime readiness;
|
|
9
|
+
- slot-owned ports;
|
|
10
|
+
- dev-server lifecycle;
|
|
11
|
+
- log sources;
|
|
12
|
+
- launch/recovery hints;
|
|
13
|
+
- headless capability.
|
|
15
14
|
|
|
16
|
-
`src/adapters/surface.ts
|
|
17
|
-
|
|
15
|
+
Implementations live in `src/adapters/{mobile,extension,core}/surface.ts`.
|
|
16
|
+
Platform-specific shell and Node operations live under `adapters/<platform>/`.
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
- `src/adapters/extension/surface.ts`
|
|
21
|
-
- `src/adapters/core/surface.ts`
|
|
18
|
+
When adding behavior:
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
```
|
|
20
|
+
1. Extend `AdapterSurface` only when every platform needs the concept.
|
|
21
|
+
2. Implement all three adapters; Core should explicitly report headless/N/A.
|
|
22
|
+
3. Call the surface from the command instead of adding adapter conditionals.
|
|
23
|
+
4. Add a registry-completeness contract and a real affected-platform check.
|
|
37
24
|
|
|
38
|
-
|
|
39
|
-
|
|
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.
|
|
25
|
+
Mechanisms unique to one command may remain platform-specific. Shared readiness,
|
|
26
|
+
ports, logs, lifecycle, and recovery language belong on the surface.
|
|
@@ -3,11 +3,27 @@
|
|
|
3
3
|
Run this from each product checkout before a release. Verify the visible outcome,
|
|
4
4
|
not only the exit code.
|
|
5
5
|
|
|
6
|
+
Run the non-visual gate first:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
yarn qa:human \
|
|
10
|
+
--extension /path/to/metamask-extension \
|
|
11
|
+
--mobile /path/to/metamask-mobile \
|
|
12
|
+
--core /path/to/metamask-core \
|
|
13
|
+
--artifacts-dir temp/human-qa
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
It verifies live readiness, installed runtime, debugger target resolution, smoke
|
|
17
|
+
evidence, and unchanged tracked product source. The checks below cover outcomes
|
|
18
|
+
that still require eyes or an intentional source edit.
|
|
19
|
+
|
|
6
20
|
## Common
|
|
7
21
|
|
|
8
22
|
- [ ] `mm-harness --version` prints the candidate version.
|
|
9
23
|
- [ ] `mm-harness doctor` detects the correct product and reports only current
|
|
10
24
|
configuration.
|
|
25
|
+
- [ ] Without `capture-helper`, `doctor` names the CDP or simulator/ADB screenshot
|
|
26
|
+
fallback and says video is unavailable.
|
|
11
27
|
- [ ] A misspelled flag explains the error and gives a runnable next command.
|
|
12
28
|
- [ ] `mm-harness actions` and `mm-harness flows` return useful, bounded discovery.
|
|
13
29
|
- [ ] `mm-harness fixtures set` either applies the fixture or names the missing
|
package/docs/UX-PRINCIPLES.md
CHANGED
|
@@ -5,7 +5,7 @@ a PR that adds a command or output path is checked against each one.
|
|
|
5
5
|
|
|
6
6
|
**Scope: the HUMAN surface.** The agent contract is exempt and inviolable: under
|
|
7
7
|
`--json`, stdout carries exactly one machine-readable envelope — no color, no
|
|
8
|
-
banners, no decorative lines
|
|
8
|
+
banners, no decorative lines. Progress/streaming exists
|
|
9
9
|
for agents too, but only ever on stderr. When a rule below conflicts with envelope
|
|
10
10
|
purity, the envelope wins.
|
|
11
11
|
|
|
@@ -1,62 +1,74 @@
|
|
|
1
1
|
# Video demo validation
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Use this checklist against the installed release before recording. Each checkout
|
|
4
|
+
auto-detects its platform, ports, and slot; the paths below are placeholders only.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
export EXTENSION_CHECKOUT=/path/to/metamask-extension
|
|
8
|
+
export MOBILE_CHECKOUT=/path/to/metamask-mobile
|
|
9
|
+
export CORE_CHECKOUT=/path/to/core
|
|
10
|
+
```
|
|
5
11
|
|
|
6
12
|
## Common
|
|
7
13
|
|
|
8
|
-
- [
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
11
|
-
- [
|
|
12
|
-
- [x] `doctor` reports current runtime fields only.
|
|
13
|
-
- [x] Recipe results print diagnostics and absolute artifact paths inline.
|
|
14
|
+
- [ ] `mm-harness --version` prints the intended release.
|
|
15
|
+
- [ ] `mm-harness doctor` explains any unavailable capability and gives one next step.
|
|
16
|
+
- [ ] Recipe results print diagnostics and absolute artifact paths inline.
|
|
17
|
+
- [ ] `git status --short` is unchanged in each product checkout after validation.
|
|
14
18
|
|
|
15
|
-
## Extension
|
|
19
|
+
## Extension
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
|
|
21
|
+
```bash
|
|
22
|
+
cd "$EXTENSION_CHECKOUT"
|
|
23
|
+
mm-harness launch --build --verify
|
|
24
|
+
mm-harness doctor
|
|
25
|
+
mm-harness actions positions
|
|
26
|
+
mm-harness flows
|
|
27
|
+
mm-harness run runner.smoke --artifacts-dir temp/demo
|
|
28
|
+
mm-harness run wallet.smoke --artifacts-dir temp/wallet-demo
|
|
29
|
+
mm-harness logs --source app
|
|
30
|
+
mm-harness debug
|
|
31
|
+
```
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
- [ ] Launch keeps an incremental webpack watcher alive.
|
|
34
|
+
- [ ] Two small source edits compile incrementally; browser refresh shows both changes.
|
|
35
|
+
- [ ] `debug` connects to the active slot's MetaMask target and opens Console.
|
|
36
|
+
- [ ] `logs --source app` shows extension logs; `--source dapp` and `--source webpack`
|
|
37
|
+
show their separate streams.
|
|
38
|
+
- [ ] Each recipe prints `diagnostics: CLEAN` or expands every warning/error inline.
|
|
39
|
+
- [ ] Each recipe prints absolute paths for its report, trace, diagnostics, screenshots,
|
|
40
|
+
and artifact manifest.
|
|
26
41
|
|
|
27
|
-
|
|
28
|
-
- [x] `mm-harness fixtures set` reads the canonical fixture and unlocks `dev1`.
|
|
29
|
-
- [x] `mm-harness call metamask.wallet.ensure_unlocked` passes from the global package.
|
|
30
|
-
- [x] `mm-harness verify` passes after fixture setup.
|
|
31
|
-
- [x] `mm-harness status` reports `WalletView`, unlocked wallet, selected account,
|
|
32
|
-
and fixture `READY`.
|
|
33
|
-
- [ ] During the recording, visually confirm the expected simulator is foregrounded.
|
|
42
|
+
## Mobile
|
|
34
43
|
|
|
35
|
-
|
|
44
|
+
```bash
|
|
45
|
+
cd "$MOBILE_CHECKOUT"
|
|
46
|
+
mm-harness launch ios --verify
|
|
47
|
+
mm-harness fixtures set
|
|
48
|
+
mm-harness call metamask.wallet.ensure_unlocked
|
|
49
|
+
mm-harness status
|
|
50
|
+
mm-harness logs --source app
|
|
51
|
+
```
|
|
36
52
|
|
|
37
|
-
- [
|
|
38
|
-
- [
|
|
39
|
-
- [
|
|
40
|
-
- [
|
|
41
|
-
- [x] Evidence prints absolute paths; diagnostics correctly reports `N/A` for headless Core.
|
|
53
|
+
- [ ] The intended simulator is running; focus changes only when explicitly requested.
|
|
54
|
+
- [ ] Fixture setup reads the canonical checkout fixture and unlocks the wallet.
|
|
55
|
+
- [ ] Status reports the live route, wallet state, account, and fixture readiness.
|
|
56
|
+
- [ ] App logs are separate from Metro logs (`mm-harness logs --source metro`).
|
|
42
57
|
|
|
43
|
-
##
|
|
58
|
+
## Core
|
|
44
59
|
|
|
45
60
|
```bash
|
|
46
|
-
|
|
47
|
-
cd /Users/deeeed/farmslot/repos/mme-2
|
|
61
|
+
cd "$CORE_CHECKOUT"
|
|
48
62
|
mm-harness doctor
|
|
49
|
-
mm-harness actions positions
|
|
50
|
-
mm-harness flows
|
|
51
63
|
mm-harness run runner.smoke --artifacts-dir temp/demo
|
|
64
|
+
```
|
|
52
65
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
mm-harness fixtures set
|
|
57
|
-
mm-harness call metamask.wallet.ensure_unlocked
|
|
66
|
+
- [ ] Doctor reports the headless controller ready.
|
|
67
|
+
- [ ] The canonical wallet fixture supplies the default account.
|
|
68
|
+
- [ ] Evidence paths are absolute; diagnostics is explicitly `N/A` for headless Core.
|
|
58
69
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
## Recording path
|
|
71
|
+
|
|
72
|
+
Show the Extension discovery and proof commands, then the equivalent Mobile and Core
|
|
73
|
+
commands. The useful story is: one auto-detected CLI, reusable team libraries,
|
|
74
|
+
parameterized recipes, app diagnostics, and proof artifacts that a human can inspect.
|