@deeeed/metamask-harness 0.82.1 → 0.84.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 +48 -0
- package/README.md +8 -1
- package/adapters/core/cleanup.sh +5 -29
- package/adapters/core/controller-import-probe.mjs +26 -0
- package/adapters/manifest.json +22 -102
- package/adapters/shared/session-lock.mjs +43 -0
- package/adapters/web-dapp/metamask-signer.mjs +212 -0
- package/dist/adapters/core/actions.js +0 -3
- package/dist/adapters/core/overlay.js +1 -5
- package/dist/adapters/core/readiness.js +133 -2
- package/dist/adapters/core/surface.js +53 -41
- package/dist/adapters/extension/extension-id.js +1 -0
- package/dist/adapters/extension/fixtures.js +60 -1
- package/dist/adapters/extension/network-observer.js +19 -206
- package/dist/adapters/extension/run.js +5 -3
- package/dist/adapters/extension/runtime.js +112 -20
- package/dist/adapters/mobile/android-gfxinfo-performance.js +3 -1
- package/dist/adapters/mobile/devices.js +5 -1
- package/dist/adapters/mobile/performance-observer.js +9 -6
- package/dist/adapters/mobile/run.js +1 -1
- package/dist/adapters/mobile/surface.js +1 -2
- package/dist/adapters/performance/trace-kinds.js +36 -0
- package/dist/adapters/plugin-surface.js +34 -34
- package/dist/adapters/session-lock.js +23 -0
- package/dist/adapters/web-dapp/console-capture.js +2 -20
- package/dist/adapters/web-dapp/run.js +31 -25
- package/dist/adapters/web-dapp/surface.js +32 -108
- package/dist/command-contract.js +1363 -630
- package/dist/commands/core-readiness.js +1 -9
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/launch/device.js +1 -1
- package/dist/doctor.js +5 -2
- package/dist/mm-harness-cli.js +228 -1210
- package/dist/performance-observation.js +28 -5
- package/docs/CONTRIBUTING.md +6 -4
- package/docs/cli-contract.md +1 -1
- package/docs/feature-guard.md +1 -1
- package/library/actions/core/perps/_controller.mjs +10 -0
- package/library/actions/extension/wallet/import.mjs +21 -4
- package/library/actions/extension/wallet/visible-session.mjs +32 -12
- package/library/actions/shared/console-collector.mjs +1 -1
- package/library/actions/web-dapp/app/launch.mjs +1 -1
- package/library/actions/web-dapp/platform/adapter-web-lib.mjs +18 -0
- package/library/actions/web-dapp/platform/hud.mjs +1 -1
- package/library/actions/web-dapp/platform/page.mjs +2 -3
- package/library/actions/web-dapp/platform/runtime.mjs +29 -178
- package/package.json +7 -6
- package/scripts/completions.sh +1 -1
- package/adapters/web-dapp/cleanup.mjs +0 -69
- package/adapters/web-dapp/inject.mjs +0 -75
- package/adapters/web-dapp/launch.mjs +0 -631
- package/adapters/web-dapp/lib/blocked-hosts.mjs +0 -24
- package/adapters/web-dapp/lib/cdp-client.mjs +0 -84
- package/adapters/web-dapp/lib/display.mjs +0 -115
- package/adapters/web-dapp/lib/hud.mjs +0 -148
- package/adapters/web-dapp/lib/policy.mjs +0 -79
- package/adapters/web-dapp/lib/processes.mjs +0 -187
- package/adapters/web-dapp/lib/readiness.mjs +0 -272
- package/adapters/web-dapp/stop.mjs +0 -38
- package/adapters/web-dapp/verify.mjs +0 -51
- package/adapters/web-dapp/wallet-host.mjs +0 -520
- package/dist/adapters/core/live-script-env.js +0 -36
- package/dist/adapters/extension/browser-cdp.js +0 -174
- package/dist/adapters/extension/performance-observer.js +0 -75
- package/dist/adapters/performance/cdp-trace.js +0 -406
- package/dist/adapters/performance/js-task-metrics.js +0 -35
- package/dist/adapters/web-dapp/doctor-checks.js +0 -33
- package/dist/adapters/web-dapp/launch.js +0 -87
- package/dist/adapters/web-dapp/overlay.js +0 -21
- package/dist/adapters/web-dapp/readiness.js +0 -10
- package/dist/adapters/web-dapp/stop.js +0 -20
- package/dist/async.js +0 -19
- package/dist/cli.js +0 -202
package/dist/mm-harness-cli.js
CHANGED
|
@@ -1,983 +1,186 @@
|
|
|
1
1
|
import "./host.js";
|
|
2
|
+
import "./adapters/surface.js";
|
|
2
3
|
import { spawnSync } from "node:child_process";
|
|
3
4
|
import fs from "node:fs";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
import {
|
|
8
|
+
createHarnessCli,
|
|
9
|
+
detectAdapter,
|
|
10
|
+
handleActions,
|
|
11
|
+
handleCall,
|
|
12
|
+
handleHarness,
|
|
13
|
+
handleLast,
|
|
14
|
+
handleLaunch,
|
|
15
|
+
handleReload,
|
|
16
|
+
handleRun,
|
|
17
|
+
handleStop,
|
|
18
|
+
harnessHost,
|
|
19
|
+
parseArgs,
|
|
20
|
+
targetPath
|
|
21
|
+
} from "@farmslot/recipe-cli/harness";
|
|
22
|
+
import { stopProjectCollector } from "../library/actions/shared/analytics/collector.mjs";
|
|
23
|
+
import { adoptPluginAdapter, afterAdapterLoad, configuredLibrarySources } from "./adapters/plugin-surface.js";
|
|
24
|
+
import { adapterRegistry } from "./adapters/registry.js";
|
|
25
|
+
import {
|
|
26
|
+
explainMissingAdapterLibrary,
|
|
27
|
+
HIDDEN_COMMANDS,
|
|
28
|
+
PUBLIC_COMMANDS,
|
|
29
|
+
REPLACED_OPTIONS
|
|
30
|
+
} from "./command-contract.js";
|
|
31
|
+
import { handleCheck } from "./commands/check.js";
|
|
32
|
+
import { handleChecklist } from "./commands/checklist.js";
|
|
33
|
+
import { handleCompletionCandidates, invalidateCompletionCache } from "./commands/completion-candidates.js";
|
|
34
|
+
import { handleConfig } from "./commands/config.js";
|
|
35
|
+
import { handleDebug } from "./commands/debug.js";
|
|
36
|
+
import { applyDeviceTargeting } from "./commands/device-target.js";
|
|
37
|
+
import { handleDoctor } from "./commands/doctor.js";
|
|
38
|
+
import { handleDomain } from "./commands/domain.js";
|
|
39
|
+
import { handleEnsureReady } from "./commands/ensure-ready.js";
|
|
40
|
+
import { handleExecutionTemplate } from "./commands/execution-template.js";
|
|
41
|
+
import { handleFixtures } from "./commands/fixtures.js";
|
|
11
42
|
import { handleHelp } from "./commands/help.js";
|
|
12
|
-
import {
|
|
43
|
+
import { handleLogs } from "./commands/logs.js";
|
|
44
|
+
import { overlayCommandOptions } from "./commands/overlay.js";
|
|
45
|
+
import { handlePin } from "./commands/pin.js";
|
|
46
|
+
import { handlePrBody } from "./commands/pr-body.js";
|
|
47
|
+
import { handlePrepare } from "./commands/prepare.js";
|
|
48
|
+
import { handleProvision } from "./commands/provision.js";
|
|
49
|
+
import { handleRecipeQuality } from "./commands/recipe-quality.js";
|
|
50
|
+
import { handleResolveExtension } from "./commands/resolve-extension.js";
|
|
51
|
+
import { handleReview } from "./commands/review.js";
|
|
52
|
+
import { handleRuntimeDecision } from "./commands/runtime-decision.js";
|
|
53
|
+
import { handleRuntimeHealth } from "./commands/runtime-health.js";
|
|
54
|
+
import { handleRuntimeLaunch } from "./commands/runtime-launch.js";
|
|
55
|
+
import { handleSelfTest } from "./commands/self-test.js";
|
|
13
56
|
import { handleSetupBase } from "./commands/setup-base.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
57
|
+
import { handleStatus } from "./commands/status.js";
|
|
58
|
+
import { handleTaskInit } from "./commands/task-init.js";
|
|
59
|
+
import { handleTutorial } from "./commands/tutorial.js";
|
|
60
|
+
import { handleUpdate, maybeNudge } from "./commands/update.js";
|
|
61
|
+
import { metaMaskEngine } from "./engine.js";
|
|
16
62
|
import { ActionManifestError } from "./manifest.js";
|
|
63
|
+
import { walletFixturePath } from "./paths.js";
|
|
17
64
|
import { configPath, hydrateLibraryPathEnv, readConfig } from "./review/knowledge.js";
|
|
18
|
-
import {
|
|
19
|
-
PUBLIC_COMMAND_CONTRACTS,
|
|
20
|
-
publicCommandNames,
|
|
21
|
-
validatePublicInvocation
|
|
22
|
-
} from "./command-contract.js";
|
|
23
65
|
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
{
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
example: "mm-harness help",
|
|
32
|
-
helpText: `mm-harness help [flags]
|
|
33
|
-
|
|
34
|
-
Loads the complete recipe guide shipped with this harness.
|
|
35
|
-
|
|
36
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
37
|
-
--target <path> Checkout path (default: cwd)
|
|
38
|
-
--json Load the same guide as structured agent context
|
|
39
|
-
|
|
40
|
-
help review [--domain <name>] prints the review guide: the base review every PR
|
|
41
|
-
gets, plus the team library's anti-pattern families, parity rule, and shared
|
|
42
|
-
package notes when --domain names a library (see mm-harness review --help).
|
|
43
|
-
|
|
44
|
-
Example:
|
|
45
|
-
mm-harness help
|
|
46
|
-
mm-harness help --json
|
|
47
|
-
mm-harness help review --domain perps`
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
name: "review",
|
|
51
|
-
summary: "Materialize a review checklist: base review + team library patterns + parity + verdict.",
|
|
52
|
-
example: "mm-harness review checklist --domain perps",
|
|
53
|
-
helpText: `mm-harness review checklist [flags]
|
|
54
|
-
|
|
55
|
-
Writes a phase-structured checklist (Setup, Base review, Domain patterns,
|
|
56
|
-
Parity, Verdict) that mm-harness checklist mark can track. Domain patterns are
|
|
57
|
-
one line per "##" section of the library's review/antipatterns.md; Parity names
|
|
58
|
-
the other platform's checkout when one resolves and says "not checked" otherwise.
|
|
59
|
-
|
|
60
|
-
Library resolution for --domain <name>: RECIPE_LIBRARY_PATH entry \u2192 engineer
|
|
61
|
-
config (mm-harness config) \u2192 sibling directory beside the checkout \u2192 shallow
|
|
62
|
-
fetch into <checkout>/.skills-cache/<name> (known libraries only). Reference
|
|
63
|
-
checkout resolution: MM_HARNESS_REF_<ADAPTER> \u2192 engineer config \u2192 sibling
|
|
64
|
-
checkout of that adapter.
|
|
65
|
-
|
|
66
|
-
--domain <name> Team library to compose (default: MM_HARNESS_DOMAIN; none = base review only)
|
|
67
|
-
--since <sha> Incremental re-review: scope the checklist to <sha>..HEAD
|
|
68
|
-
--base <ref> Base ref for the diff range (default: origin/main when present)
|
|
69
|
-
--out <file> Also write the checklist to <file>
|
|
70
|
-
--adapter, --target, --json
|
|
71
|
-
|
|
72
|
-
Example:
|
|
73
|
-
mm-harness review checklist --domain perps
|
|
74
|
-
mm-harness review checklist --domain perps --since 4dd9be9 --out temp/tasks/review/CHECKLIST.md
|
|
75
|
-
mm-harness review checklist --json`
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
name: "domain",
|
|
79
|
-
summary: "Which team library owns the change: declared value first, else owned-paths.json against the changed files.",
|
|
80
|
-
example: "mm-harness domain",
|
|
81
|
-
helpText: `mm-harness domain [flags]
|
|
82
|
-
|
|
83
|
-
Prints the domain name (or "none"). A declared --domain / MM_HARNESS_DOMAIN wins;
|
|
84
|
-
otherwise the changed files (base...HEAD, working tree, untracked) are matched
|
|
85
|
-
against owned-paths.json in every reachable library (RECIPE_LIBRARY_PATH,
|
|
86
|
-
mm-harness config, sibling directories, .skills-cache).
|
|
87
|
-
|
|
88
|
-
--domain <name> Declared domain (skips classification)
|
|
89
|
-
--base <ref> Base ref for the changed-file range (default: origin/main when present)
|
|
90
|
-
--adapter, --target, --json
|
|
91
|
-
|
|
92
|
-
Example:
|
|
93
|
-
mm-harness domain
|
|
94
|
-
mm-harness domain --json`
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
name: "pr-body",
|
|
98
|
-
summary: "Render the publishable PR body: the authored description plus the recipe and run log sections built from artifacts.",
|
|
99
|
-
example: "mm-harness pr-body render temp/tasks/dev/TAT-1",
|
|
100
|
-
helpText: `mm-harness pr-body render <task-dir> [flags]
|
|
101
|
-
|
|
102
|
-
Reads <task-dir>/artifacts/pr-description.md (the PR body the worker wrote in
|
|
103
|
-
the repository PR template shape) and inserts the machine sections rendered
|
|
104
|
-
from artifacts: "Validation Recipe" from artifacts/recipe.json, "Validation
|
|
105
|
-
Logs" from artifacts/recipe-run/report.md, and "Recipe Workflow" from
|
|
106
|
-
artifacts/workflow.mmd when it exists. Any such section the worker pasted by
|
|
107
|
-
hand is replaced. The sections go before the first checklist section, else at
|
|
108
|
-
the end. Fences are always longer than any backtick run in the content and
|
|
109
|
-
close on their own line. Writes <task-dir>/artifacts/pr-body.md.
|
|
110
|
-
|
|
111
|
-
--command <text> Recipe invocation to show above the run log
|
|
112
|
-
--out <file> Write elsewhere than artifacts/pr-body.md
|
|
113
|
-
--json Machine-readable result
|
|
114
|
-
|
|
115
|
-
Example:
|
|
116
|
-
mm-harness pr-body render temp/tasks/dev/TAT-1 --json`
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
name: "config",
|
|
120
|
-
summary: "Per-engineer locations and optional recipe advisor settings.",
|
|
121
|
-
example: "mm-harness config set references.extension ~/dev/metamask-extension",
|
|
122
|
-
helpText: `mm-harness config <list|path|get <key>|set <key> <value>|unset <key>> [--json]
|
|
123
|
-
|
|
124
|
-
Stored outside every repo in ~/.mm-harness/config.json (override: MM_HARNESS_CONFIG).
|
|
125
|
-
Keys: libraries.<name> (team library checkout), references.<mobile|extension|core|terminal>
|
|
126
|
-
(the checkout used as the parity reference), advisor.enabled (true/false),
|
|
127
|
-
advisor.provider, advisor.model, advisor.stages (plan,draft,evidence). Advisor
|
|
128
|
-
settings contain no credentials and default to disabled with planning only.
|
|
129
|
-
Env always wins over location config:
|
|
130
|
-
RECIPE_LIBRARY_PATH for libraries, MM_HARNESS_REF_<ADAPTER> for references.
|
|
131
|
-
|
|
132
|
-
Example:
|
|
133
|
-
mm-harness config set libraries.perps ~/dev/experimental-metamask-recipe-perps
|
|
134
|
-
mm-harness config set references.extension ~/dev/metamask-extension
|
|
135
|
-
mm-harness config set advisor.provider typesafe
|
|
136
|
-
mm-harness config set advisor.enabled true
|
|
137
|
-
mm-harness config list`
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
name: "tutorial",
|
|
141
|
-
summary: "Open the protected visual recipe tutorial.",
|
|
142
|
-
example: "mm-harness tutorial",
|
|
143
|
-
helpText: `mm-harness tutorial [flags]
|
|
144
|
-
|
|
145
|
-
Source checkouts open the local tutorial on port 8765. Installed releases
|
|
146
|
-
open the protected MetaMask GitHub Pages site.
|
|
147
|
-
|
|
148
|
-
--no-open Print the tutorial URL without opening it
|
|
149
|
-
--json Print version, URL, and open status as JSON
|
|
150
|
-
|
|
151
|
-
Example:
|
|
152
|
-
mm-harness tutorial`
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
name: "setup-base",
|
|
156
|
-
summary: "Bootstrap numbered MetaMask product checkouts and install their dependencies.",
|
|
157
|
-
example: "mm-harness setup-base --only core --counts core=1",
|
|
158
|
-
helpText: `mm-harness setup-base [flags]
|
|
159
|
-
|
|
160
|
-
Bootstrap numbered MetaMask Extension, Mobile, and Core checkouts under one
|
|
161
|
-
base directory, then run each checkout's pinned dependency install.
|
|
162
|
-
|
|
163
|
-
--dir <base> Destination root
|
|
164
|
-
--counts <repo=n,...> Copies per selected repository
|
|
165
|
-
--only <extension,mobile,core> Repository subset
|
|
166
|
-
--dry-run Print the plan without changing anything
|
|
167
|
-
--force Override the free-space refusal
|
|
168
|
-
--json Machine-readable terminal summary
|
|
169
|
-
--show-config Print saved preferences and exit
|
|
170
|
-
--reset-config Remove saved preferences and exit
|
|
171
|
-
--skip-harness-update Skip the installed-version notice
|
|
172
|
-
|
|
173
|
-
Example:
|
|
174
|
-
mm-harness setup-base --only core --counts core=1`
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
name: "status",
|
|
178
|
-
aliases: ["health", "home"],
|
|
179
|
-
summary: "Home dashboard for a checkout: detected adapter, next command, and (mobile) connected devices with the selected target.",
|
|
180
|
-
example: "mm-harness status",
|
|
181
|
-
helpText: `mm-harness status [flags]
|
|
182
|
-
|
|
183
|
-
Home dashboard for the current checkout \u2014 the detected adapter, the next command
|
|
184
|
-
to run, and (mobile only) the connected devices with live app state. Aliases: health, home.
|
|
185
|
-
|
|
186
|
-
--target <path> Checkout path (default: cwd)
|
|
187
|
-
--json Machine-readable envelope { adapter, target, view, devices[], next }
|
|
188
|
-
--fast Skip all live-state probes (instant output, safe for scripts)
|
|
189
|
-
--all-devices Mobile only: show every connected device instead of the slot-scoped target
|
|
190
|
-
--watch Live read-only view of the task this checkout is working through (refreshes every 2s, Ctrl-C to leave)
|
|
191
|
-
--task <dir> Task directory for the view (default: the most recently marked one under temp/tasks/)
|
|
192
|
-
|
|
193
|
-
The task view reads task files only \u2014 no probe, no launch, no write \u2014 and shows
|
|
194
|
-
the same facts whether a skill or a control plane started the run: slot and
|
|
195
|
-
device isolation, template and flow, fixture and sandbox readiness, then the
|
|
196
|
-
checklist with the time each row took, how long the current row has been
|
|
197
|
-
running, and acceptance criteria with recorded verdicts. The home dashboard
|
|
198
|
-
also shows criteria for an ongoing task. --task without --watch prints it once.
|
|
199
|
-
With --json, --watch emits one
|
|
200
|
-
object per change (newline-delimited) instead of redrawing.
|
|
201
|
-
|
|
202
|
-
The checkout view (also under "view" in --json, and printed by doctor) is what
|
|
203
|
-
this checkout is bound to: the runtime-context fields that keep it off other
|
|
204
|
-
slots' ports and devices, the recipe libraries this machine resolves, and the
|
|
205
|
-
wallet fixture it last applied.
|
|
206
|
-
|
|
207
|
-
Human output: static device list prints immediately; live-state lines append
|
|
208
|
-
after the ~2s probe window (screen, wallet, account, fixture per device).
|
|
209
|
-
By default mobile status shows the configured target only; --device <id>
|
|
210
|
-
switches the active target for that command. Other devices that answer on the
|
|
211
|
-
same Metro are reported as additional reachable targets.
|
|
212
|
-
|
|
213
|
-
The devices[] section carries per device:
|
|
214
|
-
{ platform, id, name, state, selected } always present
|
|
215
|
-
{ currentScreen, walletState, selectedAccount, fixtureStatus } when bridge reachable
|
|
216
|
-
{ liveState: 'no-bridge' } when bridge unreachable or --fast
|
|
217
|
-
|
|
218
|
-
All RN targets attached to the checkout's Metro are probed and matched to their
|
|
219
|
-
devices; a device whose target cannot be confidently matched (Metro's device
|
|
220
|
-
description matches neither the serial nor the model name) degrades to
|
|
221
|
-
liveState:'no-bridge'. An attached target whose build predates __AGENTIC__
|
|
222
|
-
reports liveState:'bridge-absent'.
|
|
223
|
-
Extension/core live-state probing is V1-pending (use doctor for runtime status).
|
|
224
|
-
|
|
225
|
-
Example:
|
|
226
|
-
mm-harness status
|
|
227
|
-
mm-harness status --json
|
|
228
|
-
mm-harness status --fast
|
|
229
|
-
mm-harness status --watch`
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
name: "checklist",
|
|
233
|
-
summary: "Mark checklist progress and close out scrubbed learning packages.",
|
|
234
|
-
example: "mm-harness checklist mark <task-dir> start",
|
|
235
|
-
helpText: `mm-harness checklist <mark|closeout> <task-dir> [step] [options]
|
|
236
|
-
|
|
237
|
-
mark delegates checklist state to @farmslot/agent-runtime. Successful complete
|
|
238
|
-
and no-change marks stage a learning package through @farmslot/handoff.
|
|
239
|
-
closeout exposes that same Handoff boundary directly; --share remains explicit.
|
|
240
|
-
The task directory is the one mm-harness task init wrote. Without a
|
|
241
|
-
checklist-target.json it marks CHECKLIST.md and writes SIGNAL.json; only a
|
|
242
|
-
role switch writes that manifest, to point at its own checklist.
|
|
243
|
-
|
|
244
|
-
Steps: start | 1 | 2 | ... | complete | no-change | blocked
|
|
245
|
-
|
|
246
|
-
Example:
|
|
247
|
-
mm-harness checklist mark temp/tasks/recipe-cook/<task> start
|
|
248
|
-
mm-harness checklist mark temp/tasks/recipe-cook/<task> 1
|
|
249
|
-
mm-harness checklist mark temp/tasks/recipe-cook/<task> sub start qa-cases --step 2 --from inputs/qa-cases.md
|
|
250
|
-
mm-harness checklist mark temp/tasks/recipe-cook/<task> sub qa-cases 1
|
|
251
|
-
mm-harness checklist mark temp/tasks/recipe-cook/<task> complete --mark-last
|
|
252
|
-
mm-harness checklist closeout temp/tasks/recipe-cook/<task> --share`
|
|
253
|
-
},
|
|
254
|
-
{
|
|
255
|
-
name: "prepare",
|
|
256
|
-
summary: "Bring this checkout to a proven-ready state and write the readiness record.",
|
|
257
|
-
example: "mm-harness prepare --platform extension",
|
|
258
|
-
helpText: `mm-harness prepare [flags]
|
|
259
|
-
|
|
260
|
-
Run the readiness chain for this checkout and record what it did as one
|
|
261
|
-
protocol readiness record (sandbox.json). Steps run in order and stop at the
|
|
262
|
-
first failure; later steps are recorded as skipped.
|
|
263
|
-
|
|
264
|
-
doctor --fix status launch --verify fixtures set verify
|
|
265
|
-
|
|
266
|
-
Core skips launch and fixtures (headless; verify is its readiness gate).
|
|
267
|
-
Mobile infers ios|android from the connected devices reported by status and
|
|
268
|
-
refuses with the numbered choice when that is ambiguous.
|
|
269
|
-
|
|
270
|
-
--target <path> Checkout path (default: cwd)
|
|
271
|
-
--platform <mobile|extension|core|terminal> Force the platform (auto-detected inside a checkout)
|
|
272
|
-
--mobile-platform <ios|android> Mobile target when status cannot decide it
|
|
273
|
-
--clear-metro Mobile only: clear Metro's transform cache in the launch step
|
|
274
|
-
--artifacts-dir <dir> Where sandbox.json and the per-step reports land
|
|
275
|
-
(default: <target>/temp/recipe/runtime)
|
|
276
|
-
--json Print the readiness record
|
|
277
|
-
|
|
278
|
-
Exit 0 when the record is ready, 1 otherwise.
|
|
279
|
-
|
|
280
|
-
Example:
|
|
281
|
-
mm-harness prepare
|
|
282
|
-
mm-harness prepare --platform mobile --mobile-platform ios --json
|
|
283
|
-
mm-harness prepare --artifacts-dir temp/tasks/fix/TAT-1/artifacts --json`
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
name: "task",
|
|
287
|
-
summary: "Create the task directory an agent works from, out of a shared execution template.",
|
|
288
|
-
example: 'mm-harness task init temp/tasks/fix/TAT-1 --flow fix-bug --template fix-bug/mobile --title "Wrong total"',
|
|
289
|
-
helpText: `mm-harness task init <task-dir> [options]
|
|
290
|
-
|
|
291
|
-
Write the task directory from a selected execution template: TASK.md, the
|
|
292
|
-
CHECKLIST.md whose boxes are the steps, a mark shim routed through
|
|
293
|
-
mm-harness checklist mark, and inputs/ (handoff.json, worker-terminal-contract.json).
|
|
294
|
-
checklist-target.json is NOT written \u2014 absent means CHECKLIST.md + SIGNAL.json.
|
|
295
|
-
|
|
296
|
-
Applied when you do not pass them: --surface skill, --mark-command for this
|
|
297
|
-
executable, and --platform from the detected checkout.
|
|
298
|
-
|
|
299
|
-
Task:
|
|
300
|
-
--title <t> Task title (required)
|
|
301
|
-
--task-text <s> | --task-file <p> Task description, inline or from a file
|
|
302
|
-
--acceptance <criterion> Authored acceptance criterion (repeatable, preserved in order)
|
|
303
|
-
--ticket <key> Ticket key
|
|
304
|
-
--source-ref <url> Where the task came from
|
|
305
|
-
|
|
306
|
-
Selection (same catalog as execution-template):
|
|
307
|
-
--flow <flow> Exact flow (required)
|
|
308
|
-
--run-mode <mode> autonomous|interactive|validation (optional;
|
|
309
|
-
set by the Farmslot control plane, omit for
|
|
310
|
-
skill/manual runs)
|
|
311
|
-
--platform <platform> Exact platform
|
|
312
|
-
--template <id> Exact template id (required)
|
|
313
|
-
--domain <domain> Exact domain
|
|
314
|
-
--dir <path> Custom flow-tree source (repeatable)
|
|
315
|
-
--domain-dir <domain=path> Domain-scoped team source (repeatable)
|
|
316
|
-
--package-templates <path> Canonical package flow-tree root
|
|
317
|
-
--package-id <id> Source label for the package root
|
|
318
|
-
--project-worker <path> Project template directory
|
|
319
|
-
--project-name <name> Source label for project templates
|
|
320
|
-
|
|
321
|
-
Identity and rendering:
|
|
322
|
-
--surface <s> Handoff surface (default: skill)
|
|
323
|
-
--project <name> --repo <owner/name> --attempt-id <id>
|
|
324
|
-
--var KEY=VALUE Template placeholder value (repeatable)
|
|
325
|
-
--task-dir-label <label> Task directory as written into the documents
|
|
326
|
-
--mode-preamble <text> Run-mode preamble for TASK.md
|
|
327
|
-
--addendum-file <path> Extra task-document section
|
|
328
|
-
--mark-command <cmd> Override the recorded mark command
|
|
329
|
-
--json Machine-readable output
|
|
330
|
-
|
|
331
|
-
Example:
|
|
332
|
-
mm-harness task init temp/tasks/fix/TAT-1 --flow fix-bug \\
|
|
333
|
-
--template fix-bug/mobile --package-templates <path> \\
|
|
334
|
-
--title "Wrong total on the receipt" --ticket TAT-1 --json`
|
|
335
|
-
},
|
|
336
|
-
{
|
|
337
|
-
name: "execution-template",
|
|
338
|
-
summary: "Discover, validate, and materialize shared agent checklists.",
|
|
339
|
-
example: "mm-harness execution-template list --package-templates <path> --json",
|
|
340
|
-
helpText: `mm-harness execution-template <list|materialize|lint|new> [options]
|
|
341
|
-
|
|
342
|
-
Shared Markdown checklist catalog used by direct and orchestrated workflows.
|
|
343
|
-
Sources use the flow-tree shape <root>/<flow>/<variant>.md.
|
|
344
|
-
|
|
345
|
-
list List compatible templates and portable source provenance.
|
|
346
|
-
materialize Select one template, copy its immutable snapshot, and optionally
|
|
347
|
-
write a provenance record.
|
|
348
|
-
lint Validate one template file or flow-tree directory.
|
|
349
|
-
new Create a minimal starter template.
|
|
350
|
-
|
|
351
|
-
Common source/filter options:
|
|
352
|
-
--dir <path> Custom flow-tree source (repeatable)
|
|
353
|
-
--domain-dir <domain=path> Domain-scoped team source (repeatable)
|
|
354
|
-
--package-templates <path> Canonical package flow-tree root
|
|
355
|
-
--package-id <id> Source label for the package root
|
|
356
|
-
--project-worker <path> Project template directory
|
|
357
|
-
--project-name <name> Source label for project templates
|
|
358
|
-
--flow <flow> Exact flow
|
|
359
|
-
--platform <platform> Exact platform
|
|
360
|
-
--run-mode <mode> autonomous|interactive|validation (optional;
|
|
361
|
-
set by the Farmslot control plane, omit for
|
|
362
|
-
skill/manual runs)
|
|
363
|
-
--domain <domain> Exact domain
|
|
364
|
-
--id <id> Exact template id
|
|
365
|
-
--json Machine-readable output
|
|
366
|
-
|
|
367
|
-
Materialize:
|
|
368
|
-
mm-harness execution-template materialize <output> --flow fix-bug \\
|
|
369
|
-
--platform mobile --id fix-bug/mobile \\
|
|
370
|
-
--package-templates <path> --provenance <path> --json`
|
|
371
|
-
},
|
|
372
|
-
{
|
|
373
|
-
name: "actions",
|
|
374
|
-
summary: "Discover typed single operations and their fields.",
|
|
375
|
-
example: "mm-harness actions --adapter mobile",
|
|
376
|
-
helpText: `mm-harness actions [query] [flags]
|
|
377
|
-
|
|
378
|
-
Discover typed single operations and their field schemas for this checkout.
|
|
379
|
-
|
|
380
|
-
query Search names, categories, fields, and descriptions (typo-tolerant)
|
|
381
|
-
--action <name> Describe one action; fuzzy-resolves like call (short or full name)
|
|
382
|
-
--matrix Compare action availability across Mobile, Extension, Core, and Terminal
|
|
383
|
-
--categories List compact action categories and counts
|
|
384
|
-
--category <name> List only one category (for example ui, wallet, or perps)
|
|
385
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
386
|
-
--target <path> Checkout path (default: cwd)
|
|
387
|
-
--raw Dump raw action registry JSON
|
|
388
|
-
--json Machine-readable output
|
|
389
|
-
|
|
390
|
-
Example:
|
|
391
|
-
mm-harness actions --adapter mobile
|
|
392
|
-
mm-harness actions --matrix --json
|
|
393
|
-
mm-harness actions positions --adapter mobile
|
|
394
|
-
mm-harness actions --adapter mobile --categories --json
|
|
395
|
-
mm-harness actions --adapter mobile --category ui --json
|
|
396
|
-
mm-harness actions --adapter mobile --action assert_orders
|
|
397
|
-
mm-harness actions --adapter extension --raw`
|
|
398
|
-
},
|
|
399
|
-
{
|
|
400
|
-
name: "stop",
|
|
401
|
-
summary: "Stop this checkout runtime (mobile Metro / Extension watcher + owned browser) and close its log windows.",
|
|
402
|
-
example: "mm-harness stop",
|
|
403
|
-
helpText: `mm-harness stop [flags]
|
|
404
|
-
|
|
405
|
-
Stop the runtime this checkout owns and close its tmux log-tail windows,
|
|
406
|
-
scoped to this checkout so concurrent slots are untouched. Idempotent \u2014
|
|
407
|
-
nothing running is success, not an error. Behavior is per platform:
|
|
408
|
-
mobile stop the port-scoped Metro dev server
|
|
409
|
-
extension stop webpack watcher, owned Chrome/CDP profile processes, viewers, and stale markers
|
|
410
|
-
core headless \u2014 no dev server to stop (teaching error)
|
|
411
|
-
|
|
412
|
-
--port <port> Metro/webpack port override; Extension CDP remains checkout-context scoped
|
|
413
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
414
|
-
--target <path> Checkout path (default: cwd)
|
|
415
|
-
--json Machine-readable output
|
|
416
|
-
|
|
417
|
-
Example:
|
|
418
|
-
mm-harness stop
|
|
419
|
-
mm-harness stop --port 8061`
|
|
420
|
-
},
|
|
421
|
-
{
|
|
422
|
-
name: "call",
|
|
423
|
-
summary: "Run one action in isolation as a one-node recipe through the real engine path (fuzzy short names; --arg k=v; same trace/evidence as run).",
|
|
424
|
-
example: "mm-harness call ensure_unlocked",
|
|
425
|
-
helpText: `mm-harness call <action> [key=value ...] [--arg k=v ...] [flags]
|
|
426
|
-
|
|
427
|
-
Run one action in isolation as a one-node recipe through the real engine path.
|
|
428
|
-
Fuzzy short-name: 'ensure_unlocked' resolves to 'metamask.wallet.ensure_unlocked'
|
|
429
|
-
if unique; ambiguous = exit 2. Pass action fields as key=value shorthand or
|
|
430
|
-
with --arg k=v; numbers, booleans, arrays, and objects are parsed as JSON-like values.
|
|
431
|
-
Actions differ per adapter \u2014 list this checkout's with:
|
|
432
|
-
mm-harness actions.
|
|
433
|
-
|
|
434
|
-
--list List actions accepted by call for this adapter; no <action> needed
|
|
435
|
-
--domain <name> With --list: filter by action domain, e.g. perps or swap-bridge
|
|
436
|
-
--source <name> With --list: filter by origin, e.g. metamask, perps, or official
|
|
437
|
-
--sort <domain|name|library> With --list: grouping/order (default: domain; JSON: name)
|
|
438
|
-
--arg k=v Action field value (repeatable; equivalent to key=value shorthand)
|
|
439
|
-
--device <udid|serial|name> Mobile only: target this device (sets IOS_SIMULATOR / ADB_SERIAL and updates agentic-runtime.json). Without it, >1 connected mobile device fails fast and lists them. Do not shut down other devices to force selection.
|
|
440
|
-
--cdp-port <port> Extension only: bind the action to this live browser runtime.
|
|
441
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
442
|
-
--target <path> Checkout path (default: cwd)
|
|
443
|
-
--artifacts-dir <dir> Where to write evidence (default: temp dir)
|
|
444
|
-
--action-manifest <path> Override the action manifest
|
|
445
|
-
--library <name=path> Add/override a recipe-library source (repeatable)
|
|
446
|
-
--heal <off|infra-only|auto> Healing policy (default: infra-only); auto-ensures the overlay
|
|
447
|
-
--json Machine-readable output
|
|
448
|
-
|
|
449
|
-
Example (real actions; run mm-harness actions for this checkout's full set):
|
|
450
|
-
mm-harness call ensure_unlocked --adapter extension # a wallet action (extension/mobile)
|
|
451
|
-
mm-harness call navigate page=perps --adapter mobile
|
|
452
|
-
mm-harness call command cmd="echo hi" --adapter core # the universal action (all adapters)
|
|
453
|
-
|
|
454
|
-
Remote feature flags (mobile applies at runtime; extension pins at launch):
|
|
455
|
-
mm-harness call metamask.feature_flags.read --adapter mobile
|
|
456
|
-
mm-harness call metamask.feature_flags.set --adapter mobile \\
|
|
457
|
-
--arg 'flags={"perpsTAT3938AbtestScreenVsBottomSheet":"treatment"}'
|
|
458
|
-
mm-harness call metamask.feature_flags.clear --adapter mobile`
|
|
459
|
-
},
|
|
460
|
-
{
|
|
461
|
-
name: "run",
|
|
462
|
-
summary: "Execute a complete proof and write its evidence.",
|
|
463
|
-
example: "mm-harness run recipe.json",
|
|
464
|
-
helpText: `mm-harness run <recipe|recipe.json> [key=value ...] [flags]
|
|
465
|
-
|
|
466
|
-
Validate and execute a complete proof, then write summary, trace, diagnostics,
|
|
467
|
-
and artifacts. Inside a checkout, the adapter, target, ports, and artifact
|
|
468
|
-
directory are normally detected automatically.
|
|
469
|
-
|
|
470
|
-
Discovery:
|
|
471
|
-
--list List complete recipes accepted by run for this adapter; no <recipe> needed
|
|
472
|
-
--domain <name> With --list: filter by recipe domain, e.g. perps or swap-bridge
|
|
473
|
-
--source <name> With --list: filter by library origin, e.g. metamask or perps
|
|
474
|
-
--sort <domain|name|library> With --list: grouping/order (default: domain; JSON: name)
|
|
475
|
-
--describe Show one recipe's parameters, composed actions/recipes, and runnable command
|
|
476
|
-
--plan Validate + print execution plan, touching nothing. Exit 5 if invalid.
|
|
477
|
-
--proof Preflight behavioral proof bindings before planning/execution; runtime evidence is still required.
|
|
478
|
-
|
|
479
|
-
Common overrides:
|
|
480
|
-
--device <udid|serial|name> Mobile only: target this device (sets IOS_SIMULATOR / ADB_SERIAL and updates agentic-runtime.json). Without it, >1 connected mobile device fails fast and lists them. Do not shut down other devices to force selection.
|
|
481
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
482
|
-
--platform <ios|android> Mobile platform preference; use --adapter for the product adapter
|
|
483
|
-
--target <path> Checkout path (default: cwd)
|
|
484
|
-
--artifacts-dir <dir> Override evidence output (default: active task/artifacts, otherwise a checkout-local temp/recipe/runs/<run>)
|
|
485
|
-
--funding-request <absolute-file> Original consented mutation request for external-mutation actions
|
|
486
|
-
--funding-preflight <absolute-file> Eligible funding preflight bound to the request bytes
|
|
487
|
-
--funding-release-proof <absolute-file> Exact release proof independently bound to funding eligibility
|
|
488
|
-
--funding-balance-proof <absolute-file> Exact balance proof and contained visible evidence chain
|
|
489
|
-
--library <name=path> Add/override a recipe-library source (repeatable)
|
|
490
|
-
--heal <off|infra-only|auto> Healing policy (default: infra-only); auto-ensures the overlay
|
|
491
|
-
--json Machine-readable output
|
|
492
|
-
--json-stream Line-flushed JSONL progress + terminal event
|
|
493
|
-
--record-video=full-run Record a video of the run
|
|
494
|
-
--hud <auto|show|hide> Recipe HUD policy (auto shows normal Mobile recipes and a headful terminal browser; hide is explicit)
|
|
495
|
-
|
|
496
|
-
Advanced integrations:
|
|
497
|
-
runtime: --cdp-port, --watcher-port/--metro-port, --runtime-dir, --slot,
|
|
498
|
-
--validation-runtime-dir, --launch-existing-dist
|
|
499
|
-
managed trust boundary (not needed for normal runs; Farmslot supplies it):
|
|
500
|
-
--source-trust, --source-kind, --source-name, --source-digest,
|
|
501
|
-
--approve-plan (binds approval to the exact reviewed plan)
|
|
502
|
-
schema: --action-manifest
|
|
503
|
-
|
|
504
|
-
Example:
|
|
505
|
-
mm-harness run wallet.smoke --describe
|
|
506
|
-
mm-harness run perps.release-market-search query=Bitcoin --plan --adapter mobile
|
|
507
|
-
mm-harness run recipe.json market=ETH --adapter extension`
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
name: "last",
|
|
511
|
-
summary: "Show the last significant command, verdict, timestamps, and evidence paths for this checkout.",
|
|
512
|
-
example: "mm-harness last --json",
|
|
513
|
-
helpText: `mm-harness last [flags]
|
|
514
|
-
|
|
515
|
-
Read the atomic per-checkout resumability journal. Discovery commands do not
|
|
516
|
-
replace it, and an interrupted process remains recorded as verdict=running.
|
|
517
|
-
|
|
518
|
-
--target <path> Checkout path (default: cwd)
|
|
519
|
-
--runtime-dir <dir> Runtime dir containing command operation records
|
|
520
|
-
--json Machine-readable envelope
|
|
521
|
-
|
|
522
|
-
Example:
|
|
523
|
-
mm-harness last --json`
|
|
524
|
-
},
|
|
525
|
-
{
|
|
526
|
-
name: "doctor",
|
|
527
|
-
summary: "Readiness check for a checkout \u2014 no app launch. --fix repairs the overlay/runtime without launching.",
|
|
528
|
-
example: "mm-harness doctor",
|
|
529
|
-
helpText: `mm-harness doctor [flags]
|
|
530
|
-
|
|
531
|
-
Readiness check for a checkout \u2014 no app launch. Reports the same checkout view
|
|
532
|
-
status does \u2014 runtime-context isolation, resolved recipe libraries, and the last
|
|
533
|
-
applied wallet fixture \u2014 so there is no hunting for files.
|
|
534
|
-
|
|
535
|
-
--fix Repair the overlay/runtime-context WITHOUT launching (no fixture reseed); --json adds fixed[]/failed[]
|
|
536
|
-
--expect-live Exit-coded liveness gate only (human verdict on stderr). Use without --print-ready when callers need pass/fail without a Farmslot indicator line
|
|
537
|
-
--print-ready Farmslot health_check mode: implies --expect-live and prints health.ready_indicator on stdout (extension/mobile: OK; core: ready)
|
|
538
|
-
--cdp-port <port> Extension CDP port for the liveness probe (env: CDP_PORT / RECIPE_CDP_PORT)
|
|
539
|
-
--device <udid|serial|name> Mobile only: target this device (env: IOS_SIMULATOR / ADB_SERIAL). doctor reports the connected devices; it never gates on ambiguity.
|
|
540
|
-
--all-devices Mobile only: show every connected device instead of the slot-scoped target
|
|
541
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
542
|
-
--target <path> Checkout path (default: cwd)
|
|
543
|
-
--runtime-dir <dir> Runtime dir containing agentic-runtime.json (relative to target)
|
|
544
|
-
--json Machine-readable output (incompatible with --print-ready)
|
|
545
|
-
|
|
546
|
-
Example:
|
|
547
|
-
mm-harness doctor
|
|
548
|
-
mm-harness doctor --fix --json
|
|
549
|
-
mm-harness doctor --adapter extension --target /path/to/checkout --cdp-port 6662 --print-ready
|
|
550
|
-
mm-harness doctor --adapter mobile --target /path/to/checkout`
|
|
551
|
-
},
|
|
552
|
-
{
|
|
553
|
-
name: "check",
|
|
554
|
-
summary: "Run bounded repo-local checks for an active git diff and write validation artifacts.",
|
|
555
|
-
example: "mm-harness check diff --profile fast",
|
|
556
|
-
helpText: `mm-harness check diff [flags]
|
|
557
|
-
|
|
558
|
-
Run bounded repo-local checks for the active git diff. Fast profile runs changed-file
|
|
559
|
-
ESLint, Prettier, and changed test files. Full profile also runs repo typecheck
|
|
560
|
-
when available. Does not launch an app or run a recipe.
|
|
561
|
-
|
|
562
|
-
--target <path> Checkout path (default: cwd)
|
|
563
|
-
--adapter <mobile|extension|core|terminal> Adapter label (auto-detected when possible)
|
|
564
|
-
--base <ref> Diff base (default: PR base, then remote HEAD, then repo fallback)
|
|
565
|
-
--profile <fast|full> Validation depth (default: fast)
|
|
566
|
-
--fix Fix changed files, then validate them
|
|
567
|
-
--artifacts-dir <dir> Write validation-summary.json/.md and per-check logs
|
|
568
|
-
--json Machine-readable envelope
|
|
569
|
-
|
|
570
|
-
Example:
|
|
571
|
-
mm-harness check diff --fix --profile fast --artifacts-dir artifacts/validation
|
|
572
|
-
mm-harness check diff --profile full --json`
|
|
573
|
-
},
|
|
574
|
-
{
|
|
575
|
-
name: "recipe-quality",
|
|
576
|
-
summary: "Build canonical recipe quality or request optional recipe advice.",
|
|
577
|
-
example: "mm-harness recipe-quality build --input compact.json --output artifacts/recipe-quality.json",
|
|
578
|
-
helpText: `mm-harness recipe-quality build|plan|advise|advisor-status [flags]
|
|
579
|
-
|
|
580
|
-
Build artifacts/recipe-quality.json from the compact fields a recipe-quality pass
|
|
581
|
-
produces (verdict + reasons + optional guidance/dimensions/findings/delta/training).
|
|
582
|
-
The artifact is validated against the RecipeQualityArtifact schema before it is
|
|
583
|
-
written \u2014 an invalid input never reaches disk. Shorthand without "build" is
|
|
584
|
-
also accepted when --input/--output are present.
|
|
585
|
-
|
|
586
|
-
Apply the quality bar from mm-harness help to the real graph and
|
|
587
|
-
evidence, then use this command to build the canonical artifact from that
|
|
588
|
-
compact verdict. An optional independent reviewer may still critique it.
|
|
589
|
-
|
|
590
|
-
--input <compact.json> Compact verdict JSON: { "verdict": "pass|warn|fail", "reasons": [..],
|
|
591
|
-
"betterVersionGuidance"?: [..], "dimensions"?: {..}, "trainingFields"?: {..}, \u2026 }
|
|
592
|
-
--output <path> Where to write the built artifact (parent dirs created)
|
|
593
|
-
--json Machine-readable envelope { status, outputPath, artifact }
|
|
594
|
-
|
|
595
|
-
Exit: 0 built \xB7 2 missing/unreadable args \xB7 5 invalid input (teaching escape names the invalid field).
|
|
596
|
-
|
|
597
|
-
Optional advice:
|
|
598
|
-
advisor-status --json
|
|
599
|
-
Resolve saved settings and overrides without reading tasks or calling a model.
|
|
600
|
-
plan --task <task.json> --adapter <mobile|extension|core|terminal> --advisor typesafe
|
|
601
|
-
Assess each acceptance criterion before a recipe exists. Task JSON contains
|
|
602
|
-
acceptanceCriteria: ["criterion", "..."] (1\u201320 entries), with optional title/description.
|
|
603
|
-
Returns known candidate refs for reuse/composition, or an explicit discovery gap.
|
|
604
|
-
advise --recipe <recipe.json> --task <TASK.md> --adapter <mobile|extension|core|terminal>
|
|
605
|
-
--advisor <provider|off> Override saved policy for this task (currently: typesafe)
|
|
606
|
-
--advisor-model <model> Override the provider default model or alias
|
|
607
|
-
--advisor-stages <csv> Select plan,draft,evidence (saved/default: plan)
|
|
608
|
-
--evidence <file.json> Explicit trace, summary, or evidence metadata to review
|
|
609
|
-
--params <json> Root recipe parameter values
|
|
610
|
-
--library <name=path> Resolve the same library sources as run (repeatable)
|
|
611
|
-
--output <advice.json> Optional separate advisory artifact
|
|
612
|
-
|
|
613
|
-
Precedence: explicit CLI > MM_HARNESS_ADVISOR[_MODEL|_STAGES] > advisor settings > disabled.
|
|
614
|
-
Set MM_HARNESS_ADVISOR to a provider or off for a Farmslot run. A key never enables advice.
|
|
615
|
-
Saved settings only run selected stages; an explicit --advisor call can request a stage directly.
|
|
616
|
-
--advisor off disables calls regardless of saved settings. No disabled advice artifact is written.
|
|
617
|
-
TypeSafe uses TYPESAFE_API_KEY. Missing keys skip advice; provider failures report unavailable.
|
|
618
|
-
Results record provider, requestedModel, and the model that answered.
|
|
619
|
-
Advice never changes recipe execution, canonical quality, or existing exit status.
|
|
620
|
-
Input must be statically valid. Context beyond the bound is skipped, never truncated.
|
|
621
|
-
|
|
622
|
-
Example:
|
|
623
|
-
mm-harness recipe-quality build --input compact.json --output artifacts/recipe-quality.json
|
|
624
|
-
mm-harness recipe-quality --input compact.json --output artifacts/recipe-quality.json
|
|
625
|
-
mm-harness recipe-quality build --input compact.json --output artifacts/recipe-quality.json --json
|
|
626
|
-
mm-harness recipe-quality advise --recipe artifacts/recipe.json --task TASK.md --adapter extension --advisor typesafe --output artifacts/recipe-advice.json --json
|
|
627
|
-
mm-harness recipe-quality plan --task task.json --adapter extension --advisor typesafe --output artifacts/recipe-plan.json --json`
|
|
628
|
-
},
|
|
629
|
-
{
|
|
630
|
-
name: "provision",
|
|
631
|
-
summary: "Install the cached Runway iOS dev client on a prepared mobile slot (no deps, no Metro).",
|
|
632
|
-
example: "mm-harness provision runway ios --adapter mobile",
|
|
633
|
-
helpText: `mm-harness provision [runway ios] [flags]
|
|
634
|
-
|
|
635
|
-
Install the cached Runway iOS dev client on the slot simulator. This is a thin
|
|
636
|
-
provisioning path only: artifact cache + simulator create + simctl install.
|
|
637
|
-
JavaScript dependencies and Metro remain dispatch-time launch concerns.
|
|
638
|
-
|
|
639
|
-
--adapter <mobile|extension|core|terminal> Target adapter (mobile supported; extension/core/terminal teach)
|
|
640
|
-
--target <path> Slot checkout path (default: cwd)
|
|
641
|
-
--platform <ios> Platform (default ios)
|
|
642
|
-
--simulator <name|udid> Override agentic-runtime.json simulator (alias: --device)
|
|
643
|
-
--device <name|udid> Alias for --simulator
|
|
644
|
-
--slot <id> Farm slot id recorded in the provision baseline
|
|
645
|
-
--watcher-port <port> Farm Metro/watcher port carried through context and Next:
|
|
646
|
-
--runtime-dir <dir> Runtime dir containing agentic-runtime.json (relative to target)
|
|
647
|
-
--runtime <id> iOS runtime id used if simulator must be created
|
|
648
|
-
--device-type <id> Device type id used if simulator must be created
|
|
649
|
-
--branch <ref> Probe this ref before default branch
|
|
650
|
-
--default-branch <ref> Fallback ref (default main)
|
|
651
|
-
--run <id> Exact GitHub Actions run id
|
|
652
|
-
--cache-root <dir> Override shared runway cache root
|
|
653
|
-
--force Reinstall even when the app is already present
|
|
654
|
-
--resolve-only Resolve artifact metadata only; no simulator/cache/install
|
|
655
|
-
--json Machine-readable envelope; progress stays stderr
|
|
656
|
-
|
|
657
|
-
Example:
|
|
658
|
-
mm-harness provision runway ios --adapter mobile --target /path/to/slot
|
|
659
|
-
mm-harness provision runway ios --adapter mobile --slot scratch-1 --runtime-dir temp/recipe/runtime-8081
|
|
660
|
-
mm-harness provision runway ios --run 28676856835 --resolve-only --json`
|
|
661
|
-
},
|
|
662
|
-
{
|
|
663
|
-
name: "install",
|
|
664
|
-
summary: "Install the per-checkout runtime overlay, or --runway to install a cached mobile dev client.",
|
|
665
|
-
example: "mm-harness install",
|
|
666
|
-
helpText: `mm-harness install [flags]
|
|
667
|
-
|
|
668
|
-
Install the per-checkout runtime overlay (for CI / agents).
|
|
669
|
-
Add --runway on a mobile slot to install the cached Runway iOS dev client only:
|
|
670
|
-
artifact cache + simulator create + simctl install. JavaScript dependencies
|
|
671
|
-
and Metro remain dispatch-time launch concerns.
|
|
672
|
-
|
|
673
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
674
|
-
--target <path> Checkout path (default: cwd)
|
|
675
|
-
--runway Thin mobile Runway artifact install instead of overlay install
|
|
676
|
-
--platform <ios> Runway platform (default ios)
|
|
677
|
-
--simulator <name|udid> Override agentic-runtime.json simulator
|
|
678
|
-
--runtime <id> iOS runtime id used if simulator must be created
|
|
679
|
-
--device-type <id> Device type id used if simulator must be created
|
|
680
|
-
--branch <ref> Probe this ref before default branch
|
|
681
|
-
--default-branch <ref> Fallback ref (default main)
|
|
682
|
-
--run <id> Exact GitHub Actions run id
|
|
683
|
-
--cache-root <dir> Override shared runway cache root
|
|
684
|
-
--force Reinstall even when the app is already present
|
|
685
|
-
--resolve-only Runway metadata only; no simulator/cache/install
|
|
686
|
-
|
|
687
|
-
Example:
|
|
688
|
-
mm-harness install
|
|
689
|
-
mm-harness install --adapter extension --target /path/to/checkout
|
|
690
|
-
mm-harness install --runway --adapter mobile --target /path/to/slot`
|
|
691
|
-
},
|
|
692
|
-
{
|
|
693
|
-
name: "verify",
|
|
694
|
-
summary: "Check the overlay/runtime is present and healthy (no launch).",
|
|
695
|
-
example: "mm-harness verify",
|
|
696
|
-
helpText: `mm-harness verify [flags]
|
|
697
|
-
|
|
698
|
-
Check the runtime overlay is present and healthy (no app launch).
|
|
699
|
-
Extension live checks infer the checkout CDP port from runtime context,
|
|
700
|
-
pool, or slot suffix when --cdp-port is omitted.
|
|
701
|
-
|
|
702
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
703
|
-
--target <path> Checkout path (default: cwd)
|
|
704
|
-
--json Machine-readable output
|
|
705
|
-
|
|
706
|
-
Example:
|
|
707
|
-
mm-harness verify
|
|
708
|
-
mm-harness verify --adapter core --target /path/to/checkout`
|
|
709
|
-
},
|
|
710
|
-
{
|
|
711
|
-
name: "cleanup",
|
|
712
|
-
summary: "Remove the installed overlay and restore the checkout.",
|
|
713
|
-
example: "mm-harness cleanup",
|
|
714
|
-
helpText: `mm-harness cleanup [flags]
|
|
715
|
-
|
|
716
|
-
Remove the installed overlay and restore the checkout.
|
|
717
|
-
|
|
718
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
719
|
-
--target <path> Checkout path (default: cwd)
|
|
720
|
-
|
|
721
|
-
Example:
|
|
722
|
-
mm-harness cleanup
|
|
723
|
-
mm-harness cleanup --adapter mobile --target /path/to/checkout`
|
|
724
|
-
},
|
|
725
|
-
{
|
|
726
|
-
name: "launch",
|
|
727
|
-
summary: "Launch the app and adapter dev server, auto-ensuring the runtime overlay first. Mobile: ios|android required.",
|
|
728
|
-
example: "mm-harness launch ios",
|
|
729
|
-
helpText: `mm-harness launch [ios|android] [flags]
|
|
730
|
-
|
|
731
|
-
Launch the app \u2014 quick relaunch by default; --build for a full native/webpack build.
|
|
732
|
-
Mobile: target is MANDATORY (ios | android). Extension: no target (--fullscreen default;
|
|
733
|
-
--sidepanel to override). core is headless (teaching error \u2014 use verify/run).
|
|
734
|
-
Terminal: starts or reuses the slot browser (visible by default) against the slot dev server.
|
|
735
|
-
Extension quick launch REUSES a healthy live runtime (reload in place, no rebuild);
|
|
736
|
-
--build is the escape hatch that always clean-builds + relaunches a fresh runtime.
|
|
737
|
-
|
|
738
|
-
--build Full production-like build + relaunch (escape hatch; skips extension reuse)
|
|
739
|
-
--clear-metro Mobile only: clear Metro's transform cache before launch
|
|
740
|
-
--verify Launch then poll CDP/bridge until ready (absorbs the old \`live\`)
|
|
741
|
-
--runway Post-launch runway check (mobile only; teaching error elsewhere)
|
|
742
|
-
--watch Persistent webpack watcher then relaunch (extension only)
|
|
743
|
-
--surface <fullscreen|sidepanel> Extension display mode (default: fullscreen)
|
|
744
|
-
--sidepanel | --fullscreen Legacy aliases for --surface
|
|
745
|
-
--url <dapp-url> Open a dapp beside the sidepanel (default: MetaMask test dapp)
|
|
746
|
-
--remote-flag <KEY=VALUE[,...]> Pin remote feature flags. VALUE is a variant name (treatment),
|
|
747
|
-
true/false, or JSON. Mobile applies it through
|
|
748
|
-
RemoteFeatureFlagController once the bridge is ready and fails the
|
|
749
|
-
launch if it does not read back; Extension pins it into the per-run
|
|
750
|
-
dist snapshot manifest (so it skips the reuse fast path).
|
|
751
|
-
--heal <off|infra-only|auto> Healing policy (default auto); bounds always enforced
|
|
752
|
-
--device <udid|name> Target simulator/device (env: IOS_SIMULATOR / ADB_SERIAL)
|
|
753
|
-
--cdp-port <port> Extension CDP port (env: CDP_PORT / RECIPE_CDP_PORT)
|
|
754
|
-
--watcher-port <port> Metro/webpack port (env: WATCHER_PORT / METRO_PORT)
|
|
755
|
-
--signer <extension|injected> Terminal: MetaMask extension (default) or the injected test wallet
|
|
756
|
-
--account <name> Terminal: wallet-fixture account (default dev1)
|
|
757
|
-
--fresh-profile Terminal: start from a new browser profile
|
|
758
|
-
--headless Terminal: hide the browser (env: TERMINAL_HEADLESS=1); default is a
|
|
759
|
-
visible window placed per slot (--headful is accepted as the default)
|
|
760
|
-
--slow-mo <ms> Terminal: pause before each UI action (env: TERMINAL_SLOW_MO; default 0)
|
|
761
|
-
--network <testnet|mainnet> Terminal: venue the slot dev server serves (default testnet)
|
|
762
|
-
--mainnet-confirmation <REAL_FUNDS> Terminal: required with --network mainnet (real funds)
|
|
763
|
-
Terminal flags are rejected for other adapters. The terminal launch
|
|
764
|
-
refuses unless the farm next dev server on --watcher-port forces
|
|
765
|
-
Hyperliquid testnet, or --network mainnet --mainnet-confirmation REAL_FUNDS
|
|
766
|
-
is passed (a recipe launch node carries network/mainnet_confirmation).
|
|
767
|
-
--adapter <mobile|extension|terminal> Target adapter (auto-detected inside a checkout)
|
|
768
|
-
--target <path> Checkout path (default: cwd)
|
|
769
|
-
--json Machine-readable summary (recovered[] / mutations[] / phase)
|
|
770
|
-
--json-stream Line-flushed JSONL progress + terminal event
|
|
771
|
-
|
|
772
|
-
Example:
|
|
773
|
-
mm-harness launch ios
|
|
774
|
-
mm-harness launch android --clear-metro --verify
|
|
775
|
-
mm-harness launch ios --build
|
|
776
|
-
mm-harness launch --verify --json
|
|
777
|
-
mm-harness launch --remote-flag perpsTAT3938AbtestScreenVsBottomSheet=treatment`
|
|
778
|
-
},
|
|
779
|
-
{
|
|
780
|
-
name: "logs",
|
|
781
|
-
summary: "Tail Metro/webpack + app logs for the active checkout.",
|
|
782
|
-
example: "mm-harness logs",
|
|
783
|
-
helpText: `mm-harness logs [flags]
|
|
784
|
-
|
|
785
|
-
Tail Metro/webpack + app logs for the active checkout.
|
|
786
|
-
Teaching error if nothing is running (points at launch).
|
|
787
|
-
|
|
788
|
-
--full Raw log tail (default = compact) (env: RECIPE_LOG_UI)
|
|
789
|
-
--window (Re)open the read-only tmux tail window for the resolved dev-server port (leaves the process untouched)
|
|
790
|
-
--events <n> Compact event count (default 10) (env: RECIPE_LOG_EVENTS)
|
|
791
|
-
--source <label> Log source per adapter \u2014 mobile: metro|app;
|
|
792
|
-
extension: extension|dapp|webpack|watcher|rebuild.
|
|
793
|
-
Core is headless (teaching error).
|
|
794
|
-
--adapter <mobile|extension|core|terminal> Target adapter (auto-detected inside a checkout)
|
|
795
|
-
--target <path> Checkout path (default: cwd)
|
|
796
|
-
--json Machine-readable output
|
|
797
|
-
|
|
798
|
-
Example:
|
|
799
|
-
mm-harness logs
|
|
800
|
-
mm-harness logs --full
|
|
801
|
-
mm-harness logs --window`
|
|
802
|
-
},
|
|
803
|
-
{
|
|
804
|
-
name: "debug",
|
|
805
|
-
summary: "Open the debug console \u2014 extension: Chrome DevTools via CDP; mobile: RN DevTools.",
|
|
806
|
-
example: "mm-harness debug",
|
|
807
|
-
helpText: `mm-harness debug [flags]
|
|
808
|
-
|
|
809
|
-
Open the debug console \u2014 extension: Chrome DevTools via CDP; mobile: RN DevTools.
|
|
810
|
-
|
|
811
|
-
--worker Extension service-worker DevTools
|
|
812
|
-
--dev-menu Mobile RN developer menu
|
|
813
|
-
--no-open Resolve target/method/endpoint without opening a UI
|
|
814
|
-
--adapter <mobile|extension> Target adapter (auto-detected inside a checkout)
|
|
815
|
-
--target <path> Checkout path (default: cwd)
|
|
816
|
-
--json Machine-readable output
|
|
817
|
-
|
|
818
|
-
Example:
|
|
819
|
-
mm-harness debug
|
|
820
|
-
mm-harness debug --worker`
|
|
821
|
-
},
|
|
822
|
-
{
|
|
823
|
-
name: "reload",
|
|
824
|
-
summary: "Reload the connected Mobile or Extension runtime without restarting its dev server.",
|
|
825
|
-
example: "mm-harness reload",
|
|
826
|
-
helpText: `mm-harness reload [flags]
|
|
827
|
-
|
|
828
|
-
Mobile broadcasts the same reload command as Metro's interactive r key.
|
|
829
|
-
Extension refreshes its loaded UI in place over CDP. Core is headless.
|
|
830
|
-
|
|
831
|
-
--adapter <mobile|extension> Target adapter (auto-detected inside a checkout)
|
|
832
|
-
--target <path> Checkout path (default: cwd)
|
|
833
|
-
--json Machine-readable output
|
|
834
|
-
|
|
835
|
-
Example:
|
|
836
|
-
mm-harness reload`
|
|
837
|
-
},
|
|
838
|
-
{
|
|
839
|
-
name: "pin",
|
|
840
|
-
summary: "Copy this installed mm-harness into an immutable, versioned store and print the copy for a task to run, so a later global upgrade cannot change a running task.",
|
|
841
|
-
example: "mm-harness pin",
|
|
842
|
-
helpText: `mm-harness pin [flags]
|
|
843
|
-
|
|
844
|
-
Copies the installed mm-harness running this command into an immutable,
|
|
845
|
-
versioned store (~/.local/share/mm-harness/pins/<version>-<hash>/; APFS clone
|
|
846
|
-
where available) and prints the copy's executable. A task records that path,
|
|
847
|
-
so \`npm i -g\` upgrading the global install never changes the harness a running
|
|
848
|
-
task runs. Idempotent: the same install returns the same pin. A source checkout
|
|
849
|
-
(MM_HARNESS_BIN) or an existing pin is printed as is.
|
|
850
|
-
|
|
851
|
-
--json Machine-readable { version, source, executable, pinned, created }
|
|
852
|
-
|
|
853
|
-
MM_HARNESS_PIN_ROOT overrides the store location.
|
|
854
|
-
|
|
855
|
-
Example:
|
|
856
|
-
mm-harness pin
|
|
857
|
-
mm-harness pin --json`
|
|
858
|
-
},
|
|
859
|
-
{
|
|
860
|
-
name: "update",
|
|
861
|
-
summary: "Update the installed mm-harness to the published latest (--check reports only; --json = {current, latest, updateAvailable}).",
|
|
862
|
-
example: "mm-harness update",
|
|
863
|
-
helpText: `mm-harness update [flags]
|
|
864
|
-
|
|
865
|
-
Update the globally-installed mm-harness to the npm registry's latest.
|
|
866
|
-
Bare form upgrades (npm i -g @deeeed/metamask-harness@latest) and prints old \u2192 new;
|
|
867
|
-
already-current exits 0.
|
|
868
|
-
|
|
869
|
-
--check Report only \u2014 exit 0 up-to-date / exit 1 update available (no install)
|
|
870
|
-
--json Machine-readable { current, latest, updateAvailable }
|
|
871
|
-
|
|
872
|
-
A passive once-a-day nudge also prints one stderr line when a newer version exists.
|
|
873
|
-
Silence it with MM_HARNESS_NO_UPDATE_CHECK=1 (auto-off in CI).
|
|
874
|
-
|
|
875
|
-
Example:
|
|
876
|
-
mm-harness update
|
|
877
|
-
mm-harness update --check --json`
|
|
878
|
-
},
|
|
879
|
-
{
|
|
880
|
-
name: "runtime-launch",
|
|
881
|
-
summary: "Launch and verify an Extension runtime or local Android release artifact.",
|
|
882
|
-
example: "mm-harness runtime-launch --adapter extension --target <checkout> --cdp-port 9222 --artifact-file <zip> --artifact-version <X.Y.Z> --artifact-sha256 <digest>",
|
|
883
|
-
helpText: `mm-harness runtime-launch --adapter <extension|mobile> --target <checkout> [flags]
|
|
884
|
-
|
|
885
|
-
Verify and run an artifact already downloaded by the validation skill. The
|
|
886
|
-
harness performs no network acquisition. Extension ZIPs run through the
|
|
887
|
-
packaged browser/CDP path; Android APKs install to one explicitly named device.
|
|
888
|
-
|
|
889
|
-
--artifact-file <path> Artifact downloaded by the validation skill
|
|
890
|
-
--artifact-version <X.Y.Z> Expected manifest or Android version name
|
|
891
|
-
--artifact-build-id <id> Android version code
|
|
892
|
-
--artifact-package-id <id> Android application ID
|
|
893
|
-
--artifact-sha256 <digest> Trusted SHA-256 from the acquisition step
|
|
894
|
-
--artifact-cache <dir> Extension artifact cache root
|
|
895
|
-
--platform <android> Mobile platform (downloaded iOS is unsupported)
|
|
896
|
-
--device <serial> Explicit Android device serial
|
|
897
|
-
--cdp-port <port> Extension CDP port
|
|
898
|
-
--chrome-user-data-dir <dir> Isolated Chrome profile path
|
|
899
|
-
--reset-profile Explicitly clear that profile; default preserves wallet state
|
|
900
|
-
--artifacts-dir <dir> Validation evidence directory
|
|
901
|
-
--start-watch Build through the checkout watcher
|
|
902
|
-
--build-lavamoat Build through the production-like path
|
|
903
|
-
--remote-flag <KEY=VARIANT> Pin checkout snapshot flags (not allowed for artifacts)
|
|
904
|
-
--json Machine-readable terminal report
|
|
905
|
-
|
|
906
|
-
Example:
|
|
907
|
-
mm-harness runtime-launch --adapter extension --target /path/to/checkout --cdp-port 9222 --artifact-file /path/to/metamask-chrome-X.Y.Z.zip --artifact-version X.Y.Z --artifact-sha256 <digest>
|
|
908
|
-
mm-harness runtime-launch --adapter mobile --platform android --target /path/to/checkout --device <serial> --artifact-file /path/to/app.apk --artifact-version X.Y.Z --artifact-build-id <code> --artifact-package-id io.metamask --artifact-sha256 <digest>`
|
|
909
|
-
},
|
|
910
|
-
{
|
|
911
|
-
name: "fixtures",
|
|
912
|
-
summary: "Manage the canonical wallet fixture (wallet DATA only) \u2014 init / sync / set / reset / generate / finalize.",
|
|
913
|
-
example: "mm-harness fixtures set",
|
|
914
|
-
helpText: `mm-harness fixtures [<init|sync|set|reset|generate|finalize>] [flags]
|
|
915
|
-
|
|
916
|
-
Manage the ONE canonical wallet fixture per checkout \u2014 wallet DATA only.
|
|
917
|
-
With no action, show the current fixture status and safe next command.
|
|
918
|
-
init Create it from --from <path>, or explicitly choose --dev for a
|
|
919
|
-
disposable public test wallet that must never hold real funds.
|
|
920
|
-
sync Refresh the wallet fixture files on the target.
|
|
921
|
-
set Apply the canonical fixture (SRP/password/accounts); the password is
|
|
922
|
-
read FROM the fixture, never typed.
|
|
923
|
-
reset Delete the current Mobile/Extension wallet, then apply and validate
|
|
924
|
-
the canonical fixture from a clean state.
|
|
925
|
-
generate Render the extension fixture-state.json from a wallet fixture, for
|
|
926
|
-
pre-launch profile prefill (extension-only). Requires --fixture and --out.
|
|
927
|
-
finalize Seed account labels/selection into the LIVE extension over CDP and
|
|
928
|
-
validate parity (extension-only, post-launch). Requires --fixture,
|
|
929
|
-
--state, --cdp-port, --extension-dir.
|
|
930
|
-
Want different accounts? Edit the fixture file directly:
|
|
931
|
-
<checkout>/temp/recipe/runtime/wallet-fixture.json
|
|
932
|
-
|
|
933
|
-
--from <path> Existing wallet fixture source (init)
|
|
934
|
-
--dev Create a disposable public test wallet (init)
|
|
935
|
-
--force Replace an existing canonical fixture (init)
|
|
936
|
-
--fixture <path> Wallet fixture path (generate/finalize input; agent override for set/sync \u2014 env: RECIPE_WALLET_FIXTURE)
|
|
937
|
-
--out <path> generate: output fixture-state.json; finalize: optional validation report
|
|
938
|
-
--state <path> finalize: the pre-launch fixture-state.json to seed
|
|
939
|
-
--cdp-port <port> finalize: CDP port of the running extension
|
|
940
|
-
--extension-dir <path> finalize: loaded extension dist (e.g. dist/chrome)
|
|
941
|
-
--extension-id-file <path> finalize: optional file to read/write the resolved extension id
|
|
942
|
-
--action-manifest <path> Extension set: override the wallet action manifest
|
|
943
|
-
--remote-flag <KEY=VALUE[,...]> set/reset: one-run override layered over the fixture's remoteFeatureFlags
|
|
944
|
-
--adapter <mobile|extension> Target adapter (auto-detected inside a checkout)
|
|
945
|
-
--target <path> Checkout path (default: cwd)
|
|
946
|
-
--device <udid|serial|name> Mobile only: target this device for sync/set
|
|
947
|
-
--json Machine-readable output
|
|
948
|
-
|
|
949
|
-
Example:
|
|
950
|
-
mm-harness fixtures init --from /secure/path/wallet-fixture.json
|
|
951
|
-
mm-harness fixtures init --dev
|
|
952
|
-
mm-harness fixtures sync
|
|
953
|
-
mm-harness fixtures set
|
|
954
|
-
mm-harness fixtures reset
|
|
955
|
-
mm-harness fixtures generate --fixture wallet-fixture.json --out fixture-state.json
|
|
956
|
-
mm-harness fixtures finalize --fixture wallet-fixture.json --state fixture-state.json --cdp-port 6661 --extension-dir dist/chrome`
|
|
66
|
+
function hostVersion() {
|
|
67
|
+
return JSON.parse(fs.readFileSync(path.join(harnessHost().packageRoot, "package.json"), "utf8")).version;
|
|
68
|
+
}
|
|
69
|
+
const stopOptions = {
|
|
70
|
+
companions: async (target) => {
|
|
71
|
+
const collector = await stopProjectCollector(target);
|
|
72
|
+
return collector.stopped && collector.pid !== null ? [{ label: "analytics collector", pid: collector.pid }] : [];
|
|
957
73
|
}
|
|
958
|
-
|
|
959
|
-
const
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
74
|
+
};
|
|
75
|
+
const targetDevice = (command, adapter, options) => applyDeviceTargeting(command, adapter, options, { gate: true, rerun: "" });
|
|
76
|
+
const runOptions = {
|
|
77
|
+
engine: metaMaskEngine,
|
|
78
|
+
targetDevice,
|
|
79
|
+
plan: {
|
|
80
|
+
// The wallet fixture `fixtures set` seeds.
|
|
81
|
+
steps: (target) => [{
|
|
82
|
+
step: "fixture.file",
|
|
83
|
+
confidence: "static",
|
|
84
|
+
status: "ok",
|
|
85
|
+
detail: fs.existsSync(walletFixturePath(target)) ? `present: ${walletFixturePath(target)}` : `absent: ${walletFixturePath(target)} (fixtures set to seed)`
|
|
86
|
+
}],
|
|
87
|
+
launchDetail: "would launch/attach the app + heal transport (Metro/Chrome/CDP) before executing"
|
|
969
88
|
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
89
|
+
};
|
|
90
|
+
const callOptions = {
|
|
91
|
+
engine: metaMaskEngine,
|
|
92
|
+
targetDevice,
|
|
93
|
+
// A wallet action makes the most useful first example.
|
|
94
|
+
exampleAction: (names) => names.find((name) => /wallet|unlock/u.test(name))
|
|
95
|
+
};
|
|
96
|
+
function overlay(command) {
|
|
97
|
+
return async (args) => {
|
|
98
|
+
if (command === "verify" && process.env.MM_HARNESS_SKIP_OVERLAY_ENSURE !== "1") {
|
|
99
|
+
try {
|
|
100
|
+
const { options } = parseArgs(args);
|
|
101
|
+
const target = targetPath(options);
|
|
102
|
+
const adapterRaw = (typeof options["adapter"] === "string" ? options["adapter"] : void 0) ?? (typeof options["platform"] === "string" ? options["platform"] : void 0) ?? detectAdapter(target);
|
|
103
|
+
if (adapterRaw && adapterRegistry.has(adapterRaw)) {
|
|
104
|
+
await handleHarness(["install", "--platform", adapterRaw, "--target", target, "--quiet"]);
|
|
105
|
+
}
|
|
106
|
+
} catch {
|
|
107
|
+
}
|
|
977
108
|
}
|
|
978
|
-
|
|
109
|
+
const code = await handleHarness([command, ...args], overlayCommandOptions);
|
|
110
|
+
if (code === 0 && command === "install") {
|
|
111
|
+
try {
|
|
112
|
+
invalidateCompletionCache(targetPath(parseArgs(args).options));
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return code;
|
|
117
|
+
};
|
|
979
118
|
}
|
|
980
|
-
|
|
119
|
+
function withManifestEnvelope(command, run) {
|
|
120
|
+
return async (args) => {
|
|
121
|
+
try {
|
|
122
|
+
return await run(args);
|
|
123
|
+
} catch (error) {
|
|
124
|
+
const own = args.includes("--") ? args.slice(0, args.indexOf("--")) : args;
|
|
125
|
+
if (!(error instanceof ActionManifestError) || !own.includes("--json")) throw error;
|
|
126
|
+
console.log(JSON.stringify({
|
|
127
|
+
schemaVersion: 1,
|
|
128
|
+
command,
|
|
129
|
+
status: "fail",
|
|
130
|
+
exitCode: 1,
|
|
131
|
+
error: { code: error.code, message: error.message, userAction: error.userAction }
|
|
132
|
+
}, null, 2));
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const PUBLIC_RUN = {
|
|
138
|
+
help: { run: (args) => handleHelp(args, { packageRoot, harnessVersion: hostVersion() }), nudge: false },
|
|
139
|
+
review: { run: handleReview },
|
|
140
|
+
domain: { run: handleDomain },
|
|
141
|
+
"pr-body": { run: handlePrBody },
|
|
142
|
+
config: { run: handleConfig },
|
|
143
|
+
tutorial: { run: (args) => handleTutorial(args, { harnessVersion: hostVersion() }), exit: "now", nudge: false },
|
|
144
|
+
"setup-base": { run: handleSetupBase, raw: true, exit: "now", nudge: false },
|
|
145
|
+
status: { run: (args) => handleStatus(parseArgs(args)) },
|
|
146
|
+
checklist: { run: handleChecklist },
|
|
147
|
+
prepare: { run: handlePrepare },
|
|
148
|
+
task: { run: handleTaskInit },
|
|
149
|
+
"execution-template": { run: handleExecutionTemplate },
|
|
150
|
+
actions: { run: (args) => handleActions(parseArgs(args), { catalog: metaMaskEngine }) },
|
|
151
|
+
stop: { run: (args) => handleStop(args, stopOptions) },
|
|
152
|
+
call: { run: (args) => handleCall(args, callOptions) },
|
|
153
|
+
run: { run: (args) => handleRun(args, runOptions) },
|
|
154
|
+
last: { run: (args) => handleLast(parseArgs(args)) },
|
|
155
|
+
doctor: { run: (args) => handleDoctor(parseArgs(args)) },
|
|
156
|
+
check: { run: handleCheck },
|
|
157
|
+
"recipe-quality": { run: handleRecipeQuality },
|
|
158
|
+
provision: { run: (args) => handleProvision(parseArgs(args)) },
|
|
159
|
+
install: { run: overlay("install") },
|
|
160
|
+
verify: { run: overlay("verify") },
|
|
161
|
+
cleanup: { run: overlay("cleanup") },
|
|
162
|
+
launch: { run: handleLaunch },
|
|
163
|
+
"runtime-launch": { run: (args) => handleRuntimeLaunch(parseArgs(args)) },
|
|
164
|
+
logs: { run: handleLogs },
|
|
165
|
+
debug: { run: handleDebug },
|
|
166
|
+
reload: { run: handleReload },
|
|
167
|
+
update: { run: handleUpdate, exit: "now", nudge: false },
|
|
168
|
+
pin: { run: handlePin, exit: "now", nudge: false },
|
|
169
|
+
fixtures: { run: handleFixtures }
|
|
170
|
+
};
|
|
171
|
+
const HIDDEN_RUN = {
|
|
172
|
+
"completion-candidates": { run: handleCompletionCandidates, nudge: false },
|
|
173
|
+
"runtime-health": { run: (args) => handleRuntimeHealth(parseArgs(args)) },
|
|
174
|
+
"runtime-decision": { run: (args) => handleRuntimeDecision(parseArgs(args, { recordIsFlag: true })) },
|
|
175
|
+
"resolve-extension": { run: (args) => handleResolveExtension(parseArgs(args)) },
|
|
176
|
+
"ensure-ready": { run: (args) => handleEnsureReady(parseArgs(args)) },
|
|
177
|
+
"self-test": { run: (args) => handleSelfTest(parseArgs(args)) },
|
|
178
|
+
// Installs/prints the bundled zsh + bash tab completion: shell tooling, no engine.
|
|
179
|
+
completions: {
|
|
180
|
+
run: (args) => spawnSync("bash", [path.join(packageRoot, "scripts", "install-completions.sh"), ...args], { stdio: "inherit" }).status ?? 1,
|
|
181
|
+
nudge: false
|
|
182
|
+
}
|
|
183
|
+
};
|
|
981
184
|
const HELP_GROUPS = [
|
|
982
185
|
{
|
|
983
186
|
title: "DAILY LOOP",
|
|
@@ -1005,249 +208,64 @@ const HELP_GROUPS = [
|
|
|
1005
208
|
commands: ["setup-base", "update", "pin"]
|
|
1006
209
|
}
|
|
1007
210
|
];
|
|
1008
|
-
function
|
|
1009
|
-
|
|
1010
|
-
if (
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
function adapterFromRuntimeContext(ctx) {
|
|
1014
|
-
const raw = typeof ctx.platform === "string" ? ctx.platform : void 0;
|
|
1015
|
-
if (!raw) return void 0;
|
|
1016
|
-
if (raw === "mobile" || raw === "ios" || raw === "android") return "mobile";
|
|
1017
|
-
if (raw === "extension" || raw === "chrome-extension") return "extension";
|
|
1018
|
-
if (raw === "core") return "core";
|
|
1019
|
-
if (raw === "terminal") return "terminal";
|
|
211
|
+
function slotAdapter(platform) {
|
|
212
|
+
if (platform === "mobile" || platform === "ios" || platform === "android") return "mobile";
|
|
213
|
+
if (platform === "extension" || platform === "chrome-extension") return "extension";
|
|
214
|
+
if (platform === "core") return "core";
|
|
215
|
+
if (platform === "terminal") return "terminal";
|
|
1020
216
|
return void 0;
|
|
1021
217
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
lines.push("(mm-harness launch ios); platform-specific needs are FLAGS on the same command. Human happy path = the bare");
|
|
1077
|
-
lines.push("command; agents add depth via flags (--json, --target, ports).");
|
|
1078
|
-
lines.push("");
|
|
1079
|
-
lines.push("SETUP \u2014 tab-completion (zsh + bash), sourced from the bundled scripts:");
|
|
1080
|
-
lines.push(" mm-harness completions install # print the lines to add to ~/.zshrc / ~/.bashrc");
|
|
1081
|
-
lines.push("");
|
|
1082
|
-
lines.push("DEV/PROD \u2014 the global npm install is prod; set MM_HARNESS_BIN to a dev checkout to override:");
|
|
1083
|
-
lines.push(" MM_HARNESS_BIN=/path/to/checkout/bin/mm-harness # unset = the installed/global bin");
|
|
1084
|
-
lines.push("");
|
|
1085
|
-
lines.push("See README.md for the workflow and docs/RECIPES.md for proof authoring.");
|
|
1086
|
-
return `${lines.join("\n")}
|
|
1087
|
-
`;
|
|
1088
|
-
}
|
|
1089
|
-
async function delegate(argv) {
|
|
1090
|
-
try {
|
|
1091
|
-
return await recipeMain(argv);
|
|
1092
|
-
} catch (error) {
|
|
1093
|
-
const own = argv.includes("--") ? argv.slice(0, argv.indexOf("--")) : argv;
|
|
1094
|
-
if (error instanceof ActionManifestError && own.includes("--json")) {
|
|
1095
|
-
console.log(JSON.stringify({
|
|
1096
|
-
schemaVersion: 1,
|
|
1097
|
-
command: argv[0],
|
|
1098
|
-
status: "fail",
|
|
1099
|
-
exitCode: 1,
|
|
1100
|
-
error: { code: error.code, message: error.message, userAction: error.userAction }
|
|
1101
|
-
}, null, 2));
|
|
1102
|
-
return 1;
|
|
1103
|
-
}
|
|
1104
|
-
console.error(error instanceof Error ? error.message : String(error));
|
|
1105
|
-
return error !== null && typeof error === "object" && "exitCode" in error && typeof error.exitCode === "number" ? error.exitCode : 1;
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
const pkgVersion = (() => {
|
|
1109
|
-
try {
|
|
1110
|
-
return JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8")).version ?? "unknown";
|
|
1111
|
-
} catch {
|
|
1112
|
-
return "unknown";
|
|
1113
|
-
}
|
|
1114
|
-
})();
|
|
1115
|
-
const program = new Command();
|
|
1116
|
-
program.name("mm-harness").description("the MetaMask recipe harness: launch the app, prove behavior, manage the runtime overlay").version(pkgVersion, "-v, --version", "Print the mm-harness version").addHelpCommand(false).helpOption("-h, --help", "Show grouped help").showHelpAfterError("(run `mm-harness --help` for the full surface)").configureHelp({ formatHelp: () => groupedHelp() });
|
|
1117
|
-
for (const command of REAL) {
|
|
1118
|
-
const registered = program.command(command.name).description(command.summary).allowUnknownOption().helpOption("-h, --help", "Show command help");
|
|
1119
|
-
if (command.aliases?.length) registered.aliases(command.aliases);
|
|
1120
|
-
registered.configureHelp({ formatHelp: () => `${command.helpText}
|
|
1121
|
-
` }).argument("[args...]").action(async () => {
|
|
1122
|
-
if (command.name === "update") {
|
|
1123
|
-
process.exit(await handleUpdate(rawArgv.slice(1)));
|
|
1124
|
-
}
|
|
1125
|
-
if (command.name === "pin") {
|
|
1126
|
-
process.exit(handlePin(rawArgv.slice(1)));
|
|
1127
|
-
}
|
|
1128
|
-
if (command.name === "help") {
|
|
1129
|
-
process.exitCode = handleHelp(rawArgv.slice(1), { packageRoot, harnessVersion: pkgVersion });
|
|
1130
|
-
return;
|
|
1131
|
-
}
|
|
1132
|
-
if (command.name === "tutorial") {
|
|
1133
|
-
process.exit(handleTutorial(rawArgv.slice(1), { harnessVersion: pkgVersion }));
|
|
1134
|
-
}
|
|
1135
|
-
process.exitCode = await withCommandJournal(command.name, rawArgv, () => delegate(rawArgv));
|
|
1136
|
-
});
|
|
1137
|
-
}
|
|
1138
|
-
const HIDDEN = [
|
|
1139
|
-
"completion-candidates",
|
|
1140
|
-
"runtime-health",
|
|
1141
|
-
"runtime-decision",
|
|
1142
|
-
"resolve-extension",
|
|
1143
|
-
"ensure-ready",
|
|
1144
|
-
"self-test"
|
|
1145
|
-
];
|
|
1146
|
-
for (const name of HIDDEN) {
|
|
1147
|
-
program.command(name, { hidden: true }).allowUnknownOption().helpOption(false).argument("[args...]").action(async () => {
|
|
1148
|
-
process.exit(await delegate(rawArgv));
|
|
1149
|
-
});
|
|
1150
|
-
}
|
|
1151
|
-
program.command("completions").description("Install/print bundled shell tab-completion (zsh + bash)").allowUnknownOption().helpOption(false).argument("[args...]").action(() => {
|
|
1152
|
-
const script = path.join(packageRoot, "scripts", "install-completions.sh");
|
|
1153
|
-
const result = spawnSync("bash", [script, ...rawArgv.slice(1)], { stdio: "inherit" });
|
|
1154
|
-
process.exit(result.status ?? 1);
|
|
1155
|
-
});
|
|
1156
|
-
const NUDGE_SKIP = ["help", "tutorial", "setup-base", "update", "pin", "completions", "completion-candidates"];
|
|
1157
|
-
if (rawArgv.length > 0 && !NUDGE_SKIP.includes(rawArgv[0])) {
|
|
1158
|
-
maybeNudge();
|
|
1159
|
-
}
|
|
1160
|
-
function targetFromArgv(argv) {
|
|
1161
|
-
const index = argv.indexOf("--target");
|
|
1162
|
-
const separate = index !== -1 ? argv[index + 1] : void 0;
|
|
1163
|
-
const inline = argv.find((argument) => argument.startsWith("--target="))?.slice("--target=".length);
|
|
1164
|
-
return path.resolve(separate ?? inline ?? process.cwd());
|
|
1165
|
-
}
|
|
1166
|
-
function hasPassthroughHelp(argv) {
|
|
1167
|
-
const divider = argv.indexOf("--");
|
|
1168
|
-
if (divider === -1) return false;
|
|
1169
|
-
return argv.slice(divider + 1).some((arg) => arg === "-h" || arg === "--help");
|
|
1170
|
-
}
|
|
1171
|
-
function isCallActionHelp(argv) {
|
|
1172
|
-
if (argv[0] !== "call") return false;
|
|
1173
|
-
if (!argv[1] || argv[1].startsWith("-")) return false;
|
|
1174
|
-
const divider = argv.indexOf("--");
|
|
1175
|
-
const scope = divider === -1 ? argv : argv.slice(0, divider);
|
|
1176
|
-
return scope.includes("--help") || scope.includes("-h");
|
|
1177
|
-
}
|
|
1178
|
-
function jsonRequestedBeforePassthrough(argv) {
|
|
1179
|
-
const divider = argv.indexOf("--");
|
|
1180
|
-
const scope = divider === -1 ? argv : argv.slice(0, divider);
|
|
1181
|
-
return scope.some((argument) => argument === "--json" || argument.startsWith("--json="));
|
|
1182
|
-
}
|
|
1183
|
-
function jsonStreamRequestedBeforePassthrough(argv) {
|
|
1184
|
-
const divider = argv.indexOf("--");
|
|
1185
|
-
const scope = divider === -1 ? argv : argv.slice(0, divider);
|
|
1186
|
-
return scope.includes("--json-stream");
|
|
1187
|
-
}
|
|
1188
|
-
function emitUsageError(error, json, jsonStream) {
|
|
1189
|
-
if (jsonStream) {
|
|
1190
|
-
const stream = new JsonStreamWriter(error.command, true);
|
|
1191
|
-
stream.error({ code: error.code, message: error.message, userAction: error.userAction });
|
|
1192
|
-
stream.complete("fail", 2);
|
|
1193
|
-
} else if (json) {
|
|
1194
|
-
process.stdout.write(
|
|
1195
|
-
`${JSON.stringify(
|
|
1196
|
-
{
|
|
1197
|
-
schemaVersion: 1,
|
|
1198
|
-
command: error.command,
|
|
1199
|
-
status: "fail",
|
|
1200
|
-
error: {
|
|
1201
|
-
code: error.code,
|
|
1202
|
-
message: error.message,
|
|
1203
|
-
userAction: error.userAction
|
|
1204
|
-
},
|
|
1205
|
-
exitCode: 2
|
|
1206
|
-
},
|
|
1207
|
-
null,
|
|
1208
|
-
2
|
|
1209
|
-
)}
|
|
1210
|
-
`
|
|
1211
|
-
);
|
|
1212
|
-
} else {
|
|
1213
|
-
const scope = error.command === "mm-harness" ? "" : ` ${error.command}`;
|
|
1214
|
-
process.stderr.write(`\u2717 mm-harness${scope}: ${error.message}
|
|
1215
|
-
Next: ${error.userAction}
|
|
1216
|
-
`);
|
|
1217
|
-
}
|
|
1218
|
-
process.exit(2);
|
|
1219
|
-
}
|
|
1220
|
-
if (rawArgv.length === 0) {
|
|
1221
|
-
process.stdout.write(groupedHelp());
|
|
1222
|
-
process.exit(0);
|
|
1223
|
-
}
|
|
1224
|
-
if (rawArgv[0] === "setup-base") {
|
|
1225
|
-
process.exit(handleSetupBase(rawArgv.slice(1)));
|
|
1226
|
-
}
|
|
1227
|
-
const preflightBypass = /* @__PURE__ */ new Set([
|
|
1228
|
-
...HIDDEN,
|
|
1229
|
-
"completions"
|
|
1230
|
-
]);
|
|
1231
|
-
if (!preflightBypass.has(rawArgv[0] ?? "")) {
|
|
1232
|
-
const usageError = validatePublicInvocation(rawArgv, PUBLIC_COMMAND_EXAMPLES);
|
|
1233
|
-
if (usageError) {
|
|
1234
|
-
emitUsageError(
|
|
1235
|
-
usageError,
|
|
1236
|
-
jsonRequestedBeforePassthrough(rawArgv),
|
|
1237
|
-
jsonStreamRequestedBeforePassthrough(rawArgv)
|
|
1238
|
-
);
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
await hydrateLibraryPathEnv({ target: targetFromArgv(rawArgv), config: readConfig(configPath()) });
|
|
1242
|
-
{
|
|
1243
|
-
const refused = await loadSelectedAdapter(rawArgv[0] ?? "", rawArgv.slice(1));
|
|
1244
|
-
if (refused !== void 0) process.exit(refused);
|
|
1245
|
-
}
|
|
1246
|
-
if (hasPassthroughHelp(rawArgv)) {
|
|
1247
|
-
process.exit(await delegate(rawArgv));
|
|
1248
|
-
}
|
|
1249
|
-
if (isCallActionHelp(rawArgv)) {
|
|
1250
|
-
const callHelp = REAL.find((command) => command.name === "call")?.helpText ?? "";
|
|
1251
|
-
process.exit(await handleCallHelp(rawArgv.slice(1), callHelp, { catalog: metaMaskEngine }));
|
|
1252
|
-
}
|
|
1253
|
-
await program.parseAsync(process.argv);
|
|
218
|
+
await createHarnessCli({
|
|
219
|
+
host: harnessHost(),
|
|
220
|
+
adapters: adapterRegistry,
|
|
221
|
+
// Every location this machine resolves a library from reaches recipe, action
|
|
222
|
+
// and template discovery, which only reads RECIPE_LIBRARY_PATH, so no command
|
|
223
|
+
// sees a narrower set than `mm-harness domain` reports.
|
|
224
|
+
libraries: { hydrate: (target) => hydrateLibraryPathEnv({ target, config: readConfig(configPath()) }) },
|
|
225
|
+
adopt: adoptPluginAdapter,
|
|
226
|
+
// A library plugin's venue policy is fenced once it loads, before any help or dispatch.
|
|
227
|
+
afterAdapterLoad,
|
|
228
|
+
// `mm-harness config set libraries.<name>` libraries, read before hydration.
|
|
229
|
+
configuredLibraries: configuredLibrarySources,
|
|
230
|
+
commands: [
|
|
231
|
+
...PUBLIC_COMMANDS.map((command) => ({
|
|
232
|
+
...command,
|
|
233
|
+
...PUBLIC_RUN[command.name],
|
|
234
|
+
run: withManifestEnvelope(command.name, PUBLIC_RUN[command.name].run)
|
|
235
|
+
})),
|
|
236
|
+
...HIDDEN_COMMANDS.map((name) => ({
|
|
237
|
+
name,
|
|
238
|
+
hidden: true,
|
|
239
|
+
...HIDDEN_RUN[name],
|
|
240
|
+
run: withManifestEnvelope(name, HIDDEN_RUN[name].run)
|
|
241
|
+
}))
|
|
242
|
+
],
|
|
243
|
+
help: {
|
|
244
|
+
description: "the MetaMask recipe harness: launch the app, prove behavior, manage the runtime overlay",
|
|
245
|
+
intro: (out) => [
|
|
246
|
+
`${out("bold", "mm-harness")} \u2014 one front door for the MetaMask recipe loop: launch the app, prove behavior, manage the runtime overlay.`,
|
|
247
|
+
"Run it from inside a MetaMask checkout; the platform (mobile | extension | core | terminal) is auto-detected.",
|
|
248
|
+
`Grammar: ${out("cmd", "mm-harness <command> [target] [flags]")} (target is a positional: ios | android; flags add agent depth; --json is the agent contract)`
|
|
249
|
+
],
|
|
250
|
+
groups: HELP_GROUPS,
|
|
251
|
+
footer: () => [
|
|
252
|
+
"ONE bin: mm-harness is the only command. Platform is auto-detected; the positional target forces it",
|
|
253
|
+
"(mm-harness launch ios); platform-specific needs are FLAGS on the same command. Human happy path = the bare",
|
|
254
|
+
"command; agents add depth via flags (--json, --target, ports).",
|
|
255
|
+
"",
|
|
256
|
+
"SETUP \u2014 tab-completion (zsh + bash), sourced from the bundled scripts:",
|
|
257
|
+
" mm-harness completions install # print the lines to add to ~/.zshrc / ~/.bashrc",
|
|
258
|
+
"",
|
|
259
|
+
"DEV/PROD \u2014 the global npm install is prod; set MM_HARNESS_BIN to a dev checkout to override:",
|
|
260
|
+
" MM_HARNESS_BIN=/path/to/checkout/bin/mm-harness # unset = the installed/global bin",
|
|
261
|
+
"",
|
|
262
|
+
"See README.md for the workflow and docs/RECIPES.md for proof authoring."
|
|
263
|
+
],
|
|
264
|
+
slotAdapter
|
|
265
|
+
},
|
|
266
|
+
// Passive update nudge: one cached stderr line if a newer version is published.
|
|
267
|
+
beforeDispatch: () => maybeNudge(),
|
|
268
|
+
catalog: metaMaskEngine,
|
|
269
|
+
replacedOptions: REPLACED_OPTIONS,
|
|
270
|
+
explainInvalidChoice: explainMissingAdapterLibrary
|
|
271
|
+
}).run();
|