@deeeed/metamask-harness 0.84.0 → 0.85.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 +34 -0
- package/adapters/extension/console-tail.mjs +11 -7
- package/adapters/extension/ensure-browser.sh +17 -18
- package/adapters/mobile/start-console-forwarder.sh +8 -0
- package/adapters/shared/resolve-slot-ports-core.mjs +48 -6
- package/dist/adapters/extension/actions.js +5 -0
- package/dist/adapters/extension/console-capture.js +18 -0
- package/dist/adapters/extension/fixtures.js +2 -0
- package/dist/adapters/extension/overlay.js +5 -4
- package/dist/adapters/extension/runtime.js +2 -0
- package/dist/adapters/mobile/launch.js +19 -2
- package/dist/adapters/mobile/provision.js +4 -2
- package/dist/adapters/mobile/run.js +2 -1
- package/dist/adapters/mobile/verify.js +15 -7
- package/dist/adapters/web-dapp/actions.js +7 -5
- package/dist/adapters.js +5 -3
- package/dist/command-contract.js +28 -19
- package/dist/commands/check.js +5 -7
- package/dist/commands/debug.js +2 -2
- package/dist/commands/doctor.js +2 -3
- package/dist/commands/domain.js +4 -3
- package/dist/commands/fixtures.js +3 -3
- package/dist/commands/help.js +6 -5
- package/dist/commands/launch/extension.js +9 -7
- package/dist/commands/logs.js +2 -2
- package/dist/commands/prepare.js +4 -4
- package/dist/commands/provision.js +2 -2
- package/dist/commands/review.js +8 -10
- package/dist/commands/runtime-launch.js +2 -0
- package/dist/commands/status.js +4 -2
- package/dist/commands/task-init.js +2 -3
- package/dist/console-classifier.js +3 -2
- package/dist/doctor.js +6 -2
- package/dist/mm-harness-cli.js +19 -6
- package/dist/paths.js +9 -4
- package/dist/recipe-security.js +1 -1
- package/dist/review/knowledge.js +10 -2
- package/dist/runner.js +18 -3
- package/docs/CONTRIBUTING.md +8 -0
- package/docs/RECIPES.md +14 -1
- package/docs/cli-contract.md +7 -6
- package/library/actions/extension/app/assert_no_console_errors.mjs +95 -0
- package/library/actions/extension/platform/cdp.mjs +26 -0
- package/library/actions/mobile/app/assert_no_console_errors.mjs +129 -0
- package/library/actions/shared/console-assert.mjs +174 -0
- package/library/actions/shared/console-collector.mjs +10 -3
- package/library/actions/shared/console-findings.mjs +108 -7
- package/library/actions/web-dapp/app/assert_no_console_errors.mjs +10 -54
- package/library/actions/web-dapp/platform/hud.mjs +2 -9
- package/library/actions/web-dapp/platform/page.mjs +62 -16
- package/library/actions/web-dapp/platform/runtime.mjs +1 -1
- package/library/diagnostics/console-allowlist.json +13 -0
- package/library/manifests/extension.action-manifest.json +36 -0
- package/library/manifests/mobile.action-manifest.json +36 -0
- package/library/manifests/web-dapp.action-manifest.json +1 -1
- package/library/recipes/core/health/check.recipe.json +40 -0
- package/library/recipes/extension/health/check.recipe.json +71 -0
- package/library/recipes/mobile/health/check.recipe.json +71 -0
- package/package.json +9 -9
- package/site/assets/help-recipes.json +2 -1
package/dist/command-contract.js
CHANGED
|
@@ -19,6 +19,12 @@ const adapterIds = (tokens) => adapterChoices(optionValues(tokens, "--library"),
|
|
|
19
19
|
env: operatorLibraryEnv()
|
|
20
20
|
});
|
|
21
21
|
const ADAPTER = { "--adapter": value(adapterIds) };
|
|
22
|
+
function selectableAdapters(libraries = []) {
|
|
23
|
+
return adapterIds(libraries.flatMap((entry) => ["--library", entry]));
|
|
24
|
+
}
|
|
25
|
+
function withAdapterList(text, libraries = []) {
|
|
26
|
+
return text.replaceAll("{adapters}", selectableAdapters(libraries).join("|"));
|
|
27
|
+
}
|
|
22
28
|
const MOBILE_PLATFORM = { "--platform": value(["ios", "android"]) };
|
|
23
29
|
const ADAPTER_OR_MOBILE_PLATFORM = { "--platform": value((tokens) => [...adapterIds(tokens), "ios", "android"]) };
|
|
24
30
|
const DEVICE = { "--device": value() };
|
|
@@ -88,7 +94,7 @@ const PUBLIC_COMMANDS = [
|
|
|
88
94
|
|
|
89
95
|
Loads the complete recipe guide shipped with this harness.
|
|
90
96
|
|
|
91
|
-
--adapter <
|
|
97
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
92
98
|
--target <path> Checkout path (default: cwd)
|
|
93
99
|
--json Load the same guide as structured agent context
|
|
94
100
|
|
|
@@ -289,6 +295,7 @@ Example:
|
|
|
289
295
|
Home dashboard for the current checkout \u2014 the detected adapter, the next command
|
|
290
296
|
to run, and (mobile only) the connected devices with live app state. Aliases: health, home.
|
|
291
297
|
|
|
298
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
292
299
|
--target <path> Checkout path (default: cwd)
|
|
293
300
|
--json Machine-readable envelope { adapter, target, view, devices[], next }
|
|
294
301
|
--fast Skip all live-state probes (instant output, safe for scripts)
|
|
@@ -334,7 +341,7 @@ Example:
|
|
|
334
341
|
mm-harness status --fast
|
|
335
342
|
mm-harness status --watch`,
|
|
336
343
|
contract: {
|
|
337
|
-
options: options(HELP, JSON, TARGET, DEVICE, {
|
|
344
|
+
options: options(HELP, JSON, TARGET, ADAPTER, ADAPTER_OR_MOBILE_PLATFORM, DEVICE, {
|
|
338
345
|
"--fast": bool(),
|
|
339
346
|
"--all-devices": bool(),
|
|
340
347
|
"--watch": bool(),
|
|
@@ -429,7 +436,7 @@ Example:
|
|
|
429
436
|
refuses with the numbered choice when that is ambiguous.
|
|
430
437
|
|
|
431
438
|
--target <path> Checkout path (default: cwd)
|
|
432
|
-
--platform <
|
|
439
|
+
--platform <{adapters}> Force the platform (auto-detected inside a checkout)
|
|
433
440
|
--mobile-platform <ios|android> Mobile target when status cannot decide it
|
|
434
441
|
--clear-metro Mobile only: clear Metro's transform cache in the launch step
|
|
435
442
|
--artifacts-dir <dir> Where sandbox.json and the per-step reports land
|
|
@@ -633,7 +640,7 @@ Materialize:
|
|
|
633
640
|
--matrix Compare action availability across Mobile, Extension, Core, and Terminal
|
|
634
641
|
--categories List compact action categories and counts
|
|
635
642
|
--category <name> List only one category (for example ui, wallet, or perps)
|
|
636
|
-
--adapter <
|
|
643
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
637
644
|
--target <path> Checkout path (default: cwd)
|
|
638
645
|
--raw Dump raw action registry JSON
|
|
639
646
|
--json Machine-readable output
|
|
@@ -674,7 +681,7 @@ Example:
|
|
|
674
681
|
core headless \u2014 no dev server to stop (teaching error)
|
|
675
682
|
|
|
676
683
|
--port <port> Metro/webpack port override; Extension CDP remains checkout-context scoped
|
|
677
|
-
--adapter <
|
|
684
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
678
685
|
--target <path> Checkout path (default: cwd)
|
|
679
686
|
--json Machine-readable output
|
|
680
687
|
|
|
@@ -707,7 +714,7 @@ Example:
|
|
|
707
714
|
--sort <domain|name|library> With --list: grouping/order (default: domain; JSON: name)
|
|
708
715
|
--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.
|
|
709
716
|
--cdp-port <port> Extension only: bind the action to this live browser runtime.
|
|
710
|
-
--adapter <
|
|
717
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
711
718
|
--target <path> Checkout path (default: cwd)
|
|
712
719
|
--artifacts-dir <dir> Where to write evidence (default: <task>/artifacts/calls/<action>-<id>
|
|
713
720
|
inside a task, else temp/recipe/calls/<action>-<id>)
|
|
@@ -765,7 +772,7 @@ Discovery:
|
|
|
765
772
|
|
|
766
773
|
Common overrides:
|
|
767
774
|
--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.
|
|
768
|
-
--adapter <
|
|
775
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
769
776
|
--platform <ios|android> Mobile platform preference; use --adapter for the product adapter
|
|
770
777
|
--target <path> Checkout path (default: cwd)
|
|
771
778
|
--artifacts-dir <dir> Override evidence output (default: active task/artifacts, otherwise a checkout-local temp/recipe/runs/<run>)
|
|
@@ -778,7 +785,7 @@ Common overrides:
|
|
|
778
785
|
--json Machine-readable output
|
|
779
786
|
--json-stream Line-flushed JSONL progress + terminal event
|
|
780
787
|
--record-video=full-run Record a video of the run
|
|
781
|
-
--hud <
|
|
788
|
+
--hud <show|hide> Recipe HUD: each node's intent drawn over the app on every adapter, headless included (default: show)
|
|
782
789
|
|
|
783
790
|
Advanced integrations:
|
|
784
791
|
runtime: --cdp-port, --watcher-port, --runtime-dir, --slot,
|
|
@@ -801,7 +808,7 @@ Example:
|
|
|
801
808
|
"--plan": bool(),
|
|
802
809
|
"--proof": bool(),
|
|
803
810
|
"--describe": bool(),
|
|
804
|
-
"--hud": value(["
|
|
811
|
+
"--hud": value(["show", "hide"])
|
|
805
812
|
}),
|
|
806
813
|
positionals: [{ label: "recipe" }],
|
|
807
814
|
minimumPositionals: 1,
|
|
@@ -850,7 +857,7 @@ Example:
|
|
|
850
857
|
--cdp-port <port> Extension CDP port for the liveness probe (env: CDP_PORT / RECIPE_CDP_PORT)
|
|
851
858
|
--device <udid|serial|name> Mobile only: target this device (env: IOS_SIMULATOR / ADB_SERIAL). doctor reports the connected devices; it never gates on ambiguity.
|
|
852
859
|
--all-devices Mobile only: show every connected device instead of the slot-scoped target
|
|
853
|
-
--adapter <
|
|
860
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
854
861
|
--target <path> Checkout path (default: cwd)
|
|
855
862
|
--runtime-dir <dir> Runtime dir containing agentic-runtime.json (relative to target)
|
|
856
863
|
--json Machine-readable output (incompatible with --print-ready)
|
|
@@ -882,7 +889,7 @@ Example:
|
|
|
882
889
|
when available. Does not launch an app or run a recipe.
|
|
883
890
|
|
|
884
891
|
--target <path> Checkout path (default: cwd)
|
|
885
|
-
--adapter <
|
|
892
|
+
--adapter <{adapters}> Adapter label (auto-detected when possible)
|
|
886
893
|
--base <ref> Diff base (default: PR base, then remote HEAD, then repo fallback)
|
|
887
894
|
--profile <fast|full> Validation depth (default: fast)
|
|
888
895
|
--fix Fix changed files, then validate them
|
|
@@ -929,11 +936,11 @@ Example:
|
|
|
929
936
|
Optional advice:
|
|
930
937
|
advisor-status --json
|
|
931
938
|
Resolve saved settings and overrides without reading tasks or calling a model.
|
|
932
|
-
plan --task <task.json> --adapter <
|
|
939
|
+
plan --task <task.json> --adapter <{adapters}> --advisor typesafe
|
|
933
940
|
Assess each acceptance criterion before a recipe exists. Task JSON contains
|
|
934
941
|
acceptanceCriteria: ["criterion", "..."] (1\u201320 entries), with optional title/description.
|
|
935
942
|
Returns known candidate refs for reuse/composition, or an explicit discovery gap.
|
|
936
|
-
advise --recipe <recipe.json> --task <TASK.md> --adapter <
|
|
943
|
+
advise --recipe <recipe.json> --task <TASK.md> --adapter <{adapters}>
|
|
937
944
|
--advisor <provider|off> Override saved policy for this task (currently: typesafe)
|
|
938
945
|
--advisor-model <model> Override the provider default model or alias
|
|
939
946
|
--advisor-stages <csv> Select plan,draft,evidence (saved/default: plan)
|
|
@@ -983,7 +990,7 @@ Example:
|
|
|
983
990
|
provisioning path only: artifact cache + simulator create + simctl install.
|
|
984
991
|
JavaScript dependencies and Metro remain dispatch-time launch concerns.
|
|
985
992
|
|
|
986
|
-
--adapter <
|
|
993
|
+
--adapter <{adapters}> Target adapter (mobile supported; the others teach)
|
|
987
994
|
--target <path> Slot checkout path (default: cwd)
|
|
988
995
|
--platform <ios> Platform (default ios)
|
|
989
996
|
--simulator <name|udid> Override agentic-runtime.json simulator (alias: --device)
|
|
@@ -1027,7 +1034,7 @@ Example:
|
|
|
1027
1034
|
artifact cache + simulator create + simctl install. JavaScript dependencies
|
|
1028
1035
|
and Metro remain dispatch-time launch concerns.
|
|
1029
1036
|
|
|
1030
|
-
--adapter <
|
|
1037
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
1031
1038
|
--target <path> Checkout path (default: cwd)
|
|
1032
1039
|
--runway Thin mobile Runway artifact install instead of overlay install
|
|
1033
1040
|
--platform <ios> Runway platform (default ios)
|
|
@@ -1062,7 +1069,7 @@ Example:
|
|
|
1062
1069
|
Extension live checks infer the checkout CDP port from runtime context,
|
|
1063
1070
|
pool, or slot suffix when --cdp-port is omitted.
|
|
1064
1071
|
|
|
1065
|
-
--adapter <
|
|
1072
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
1066
1073
|
--target <path> Checkout path (default: cwd)
|
|
1067
1074
|
--json Machine-readable output
|
|
1068
1075
|
|
|
@@ -1082,7 +1089,7 @@ Example:
|
|
|
1082
1089
|
|
|
1083
1090
|
Remove the installed overlay and restore the checkout.
|
|
1084
1091
|
|
|
1085
|
-
--adapter <
|
|
1092
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
1086
1093
|
--target <path> Checkout path (default: cwd)
|
|
1087
1094
|
|
|
1088
1095
|
Example:
|
|
@@ -1235,7 +1242,7 @@ Example:
|
|
|
1235
1242
|
--source <label> Log source per adapter \u2014 mobile: metro|app;
|
|
1236
1243
|
extension: extension|dapp|webpack|watcher|rebuild.
|
|
1237
1244
|
Core is headless (teaching error).
|
|
1238
|
-
--adapter <
|
|
1245
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
1239
1246
|
--target <path> Checkout path (default: cwd)
|
|
1240
1247
|
--json Machine-readable output
|
|
1241
1248
|
|
|
@@ -1458,5 +1465,7 @@ export {
|
|
|
1458
1465
|
HIDDEN_COMMANDS,
|
|
1459
1466
|
PUBLIC_COMMANDS,
|
|
1460
1467
|
REPLACED_OPTIONS,
|
|
1461
|
-
explainMissingAdapterLibrary
|
|
1468
|
+
explainMissingAdapterLibrary,
|
|
1469
|
+
selectableAdapters,
|
|
1470
|
+
withAdapterList
|
|
1462
1471
|
};
|
package/dist/commands/check.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { EXIT, contextAdapter, usageOut, optionFlag, optionString, parseArgs, shellQuote } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
|
-
import "../adapters/surface.js";
|
|
6
5
|
const USAGE = "mm-harness check diff [--fix] [--target <repo>] [--adapter <adapter>] [--base <ref>] [--profile fast|full] [--artifacts-dir <dir>] [--json]";
|
|
7
6
|
const JS_TS_EXT_RE = /\.(?:c|m)?jsx?$|\.tsx?$/u;
|
|
8
7
|
const FORMAT_EXT_RE = /\.(?:c|m)?jsx?$|\.tsx?$|\.json$|\.md$|\.css$|\.scss$|\.ya?ml$/u;
|
|
@@ -20,12 +19,11 @@ async function handleCheck(argv) {
|
|
|
20
19
|
return usageOut(json, "check", message, USAGE);
|
|
21
20
|
}
|
|
22
21
|
const target = path.resolve(optionString(options, "target") ?? process.cwd());
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return usageOut(json, "check", `unsupported adapter '${detected}'`, USAGE);
|
|
22
|
+
const platform = optionString(options, "adapter") ? void 0 : optionString(options, "platform");
|
|
23
|
+
if (platform === "ios" || platform === "android") {
|
|
24
|
+
return usageOut(json, "check", `unsupported adapter '${platform}'`, USAGE);
|
|
27
25
|
}
|
|
28
|
-
const adapter =
|
|
26
|
+
const adapter = contextAdapter(target);
|
|
29
27
|
const profileInput = optionString(options, "profile");
|
|
30
28
|
if (profileInput && profileInput !== "fast" && profileInput !== "full") {
|
|
31
29
|
return usageOut(json, "check", "--profile must be fast or full", USAGE);
|
package/dist/commands/debug.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { adapterDetectNext, EXIT, flag, parseFlags,
|
|
1
|
+
import { adapterDetectNext, EXIT, flag, parseFlags, contextAdapter, spawnScript, targetOf, usageOut } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { runnerDir } from "../paths.js";
|
|
4
4
|
import { getAdapterSurface } from "../adapters/surface.js";
|
|
@@ -7,7 +7,7 @@ async function handleDebug(argv) {
|
|
|
7
7
|
const { options } = parseFlags(argv, DEBUG_BOOLEANS);
|
|
8
8
|
const json = flag(options, "json");
|
|
9
9
|
const target = targetOf(options);
|
|
10
|
-
const adapter =
|
|
10
|
+
const adapter = contextAdapter(target);
|
|
11
11
|
if (!adapter) return usageOut(json, "debug", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
|
|
12
12
|
const surface = getAdapterSurface(adapter);
|
|
13
13
|
if (surface.headless) return usageOut(json, "debug", `${adapter} is headless; there is no debug console.`, surface.hints.relaunch);
|
package/dist/commands/doctor.js
CHANGED
|
@@ -2,7 +2,7 @@ import { execFileSync } from "node:child_process";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { featureFlagReport } from "../feature-flags.js";
|
|
5
|
-
import { adapterPluginChecks, color, acquireCheckoutLock,
|
|
5
|
+
import { adapterPluginChecks, color, acquireCheckoutLock, contextAdapter, resolveRuntimeContextPath, ensureOverlay, newHealState, recipeRunning, adapterDetectNext, checkoutBusyOut, EXIT, usageOut, actionManifestPathOption, applyRuntimeDirOption, optionFlag, optionString, shellQuote, targetPath } from "@farmslot/recipe-cli/harness";
|
|
6
6
|
import { collectCheckoutView, renderCheckoutView } from "../checkout-view.js";
|
|
7
7
|
import { createDoctorReport, fixtureSummary, requiredDoctorCheckSummary } from "../doctor.js";
|
|
8
8
|
import { assertAdapter, runnerDir } from "../paths.js";
|
|
@@ -33,8 +33,7 @@ async function handleDoctor({ options }) {
|
|
|
33
33
|
const expectLive = optionFlag(options, "expectLive") || printReady;
|
|
34
34
|
const allDevices = optionFlag(options, "allDevices");
|
|
35
35
|
const platformOption = optionString(options, "platform");
|
|
36
|
-
const
|
|
37
|
-
const adapter = explicitAdapter ?? detectAdapter(target);
|
|
36
|
+
const adapter = contextAdapter(target);
|
|
38
37
|
if (!adapter) {
|
|
39
38
|
return usageOut(json, "doctor", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
|
|
40
39
|
}
|
package/dist/commands/domain.js
CHANGED
|
@@ -4,7 +4,8 @@ import {
|
|
|
4
4
|
classifyDomain,
|
|
5
5
|
configPath,
|
|
6
6
|
discoverLibraries,
|
|
7
|
-
readConfig
|
|
7
|
+
readConfig,
|
|
8
|
+
REVIEW_ADAPTERS
|
|
8
9
|
} from "../review/knowledge.js";
|
|
9
10
|
import { adapterFromOptions } from "./review.js";
|
|
10
11
|
async function handleDomain(argv) {
|
|
@@ -12,14 +13,14 @@ async function handleDomain(argv) {
|
|
|
12
13
|
const target = targetPath(parsed.options);
|
|
13
14
|
const json = optionFlag(parsed.options, "json");
|
|
14
15
|
const declared = optionString(parsed.options, "domain") ?? process.env.MM_HARNESS_DOMAIN;
|
|
15
|
-
const detected = adapterFromOptions(
|
|
16
|
+
const detected = adapterFromOptions();
|
|
16
17
|
const adapter = detected === "unscoped" ? void 0 : detected;
|
|
17
18
|
if (declared) {
|
|
18
19
|
emit(json, { domain: declared, source: "declared", adapter: adapter ?? null, target });
|
|
19
20
|
return 0;
|
|
20
21
|
}
|
|
21
22
|
if (!adapter) {
|
|
22
|
-
throw usageError(
|
|
23
|
+
throw usageError(`No MetaMask checkout detected: pass --adapter <${REVIEW_ADAPTERS.join("|")}> or --domain <name>.`);
|
|
23
24
|
}
|
|
24
25
|
const config = readConfig(configPath());
|
|
25
26
|
const libraries = discoverLibraries({ target, config });
|
|
@@ -4,7 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { runnerDir, walletFixturePath } from "../paths.js";
|
|
5
5
|
import { getAdapterSurface } from "../adapters/surface.js";
|
|
6
6
|
import { fixtureFileSummary, fixtureSummary } from "../doctor.js";
|
|
7
|
-
import { acquireCheckoutLock, adapterDetectNext, checkoutBusyOut, EXIT, flag, parseFlags,
|
|
7
|
+
import { acquireCheckoutLock, adapterDetectNext, checkoutBusyOut, EXIT, flag, parseFlags, contextAdapter, scriptOverride, spawnScript, spawnScriptStreaming, str, targetOf, usageOut } from "@farmslot/recipe-cli/harness";
|
|
8
8
|
import { applyDeviceTargeting } from "./device-target.js";
|
|
9
9
|
import { FeatureFlagSpecError, fixtureFeatureFlags, parseRemoteFlagSpec } from "../feature-flags.js";
|
|
10
10
|
const FIXTURES_BOOLEANS = /* @__PURE__ */ new Set(["dev", "force", "json"]);
|
|
@@ -38,7 +38,7 @@ function fixturesStatus(options) {
|
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
40
|
const target = targetOf(options);
|
|
41
|
-
const adapter =
|
|
41
|
+
const adapter = contextAdapter(target);
|
|
42
42
|
if (!adapter) {
|
|
43
43
|
return usageOut(json, "fixtures", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
|
|
44
44
|
}
|
|
@@ -114,7 +114,7 @@ async function handleFixturesLocked(argv) {
|
|
|
114
114
|
);
|
|
115
115
|
}
|
|
116
116
|
const target = targetOf(options);
|
|
117
|
-
const adapter =
|
|
117
|
+
const adapter = contextAdapter(target);
|
|
118
118
|
if (!adapter) {
|
|
119
119
|
return usageOut(json, "fixtures", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
|
|
120
120
|
}
|
package/dist/commands/help.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { color,
|
|
3
|
+
import { color, contextAdapter, parseArgs, targetPath } from "@farmslot/recipe-cli/harness";
|
|
4
|
+
import { selectableAdapters } from "../command-contract.js";
|
|
4
5
|
import { handleHelpReview } from "./review.js";
|
|
5
6
|
import "../adapters/surface.js";
|
|
6
|
-
const
|
|
7
|
+
const unscopedNext = () => `cd into a MetaMask checkout or pass --adapter <${selectableAdapters().join("|")}>`;
|
|
7
8
|
function validHelpLine(value) {
|
|
8
9
|
return typeof value === "string" || Boolean(value && typeof value.text === "string" && Array.isArray(value.adapters) && value.adapters.length > 0 && value.adapters.every((adapter) => ["mobile", "extension", "core", "web-dapp"].includes(adapter)));
|
|
9
10
|
}
|
|
@@ -35,7 +36,7 @@ function recipeHelpPayload(topic, harnessVersion, adapter, target) {
|
|
|
35
36
|
harnessVersion,
|
|
36
37
|
recipeProtocolVersion: topic.recipeProtocolVersion,
|
|
37
38
|
adapter,
|
|
38
|
-
...adapter === "unscoped" ? { next:
|
|
39
|
+
...adapter === "unscoped" ? { next: unscopedNext() } : {},
|
|
39
40
|
target,
|
|
40
41
|
topic: topic.topic,
|
|
41
42
|
title: topic.title,
|
|
@@ -58,7 +59,7 @@ function renderRecipeHelp(topic, harnessVersion, adapter) {
|
|
|
58
59
|
paint("warn", topic.scopeNotice),
|
|
59
60
|
`Visual tutorial: ${paint("cmd", "mm-harness tutorial")}`
|
|
60
61
|
];
|
|
61
|
-
if (adapter === "unscoped") lines.push(paint("warn", `No MetaMask checkout detected. Next: ${
|
|
62
|
+
if (adapter === "unscoped") lines.push(paint("warn", `No MetaMask checkout detected. Next: ${unscopedNext()}.`));
|
|
62
63
|
for (const [index, section] of scopedSections(topic, adapter).entries()) {
|
|
63
64
|
lines.push("", paint("label", `${index + 1}. ${section.title}`), ` ${section.instruction}`);
|
|
64
65
|
for (const detail of section.details) lines.push(` - ${detail}`);
|
|
@@ -72,7 +73,7 @@ function handleHelp(argv, context) {
|
|
|
72
73
|
const parsed = parseArgs(argv);
|
|
73
74
|
if (parsed.positional[0] === "review") return handleHelpReview(argv, context.harnessVersion);
|
|
74
75
|
const target = targetPath(parsed.options);
|
|
75
|
-
const adapter =
|
|
76
|
+
const adapter = contextAdapter(target) ?? "unscoped";
|
|
76
77
|
const topic = loadRecipeHelp(context.packageRoot);
|
|
77
78
|
const payload = recipeHelpPayload(topic, context.harnessVersion, adapter, target);
|
|
78
79
|
if (parsed.options.json === true) {
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import { checkExtensionRuntimeHealth } from "../../adapters/extension/runtime.js";
|
|
25
25
|
import { ensureHarnessFresh } from "../../adapters/harness-freshness.js";
|
|
26
26
|
import { isExtensionWatcherLive, stopExtensionWatcher } from "../../adapters/slot-ports.js";
|
|
27
|
+
import { recordExtensionConsoleLaunch } from "../../adapters/extension/console-capture.js";
|
|
27
28
|
import { readExtensionPinnedFlags } from "../../adapters/extension/feature-flags.js";
|
|
28
29
|
import { sameFeatureFlags } from "../../feature-flags.js";
|
|
29
30
|
const { CdpSession } = await importRecipeHarnessRuntimeCdp();
|
|
@@ -108,6 +109,14 @@ Next: ${block.userAction}`
|
|
|
108
109
|
}
|
|
109
110
|
await ensureHarnessFresh(target, "extension");
|
|
110
111
|
restoreRequestedPorts();
|
|
112
|
+
if (!reusable && artifactLaunchable && remoteFlags) {
|
|
113
|
+
return {
|
|
114
|
+
status: EXIT.infra,
|
|
115
|
+
output: `REMOTE_FLAG_NOT_PINNABLE: the remote feature-flag pin '${remoteFlags.spec}' (from --remote-flag and the wallet fixture's remoteFeatureFlags) cannot be applied to a verified release artifact; the artifact's manifest is signed evidence and is never rewritten.
|
|
116
|
+
Next: drop --remote-flag and remove remoteFeatureFlags from the wallet fixture to validate the artifact as shipped, or validate the variant on a source checkout launched without the artifact.`
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
recordExtensionConsoleLaunch(target);
|
|
111
120
|
if (wantWatch) {
|
|
112
121
|
const startWatchSh = path.join(runnerDir, "adapters/extension/start-watch.sh");
|
|
113
122
|
const watchArgs = ["--target", target, "--runner-bin", path.join(runnerDir, "bin/mm-harness")];
|
|
@@ -128,13 +137,6 @@ Next: ${block.userAction}`
|
|
|
128
137
|
return extensionReattach(target, displayMode);
|
|
129
138
|
}
|
|
130
139
|
if (artifactLaunchable) {
|
|
131
|
-
if (remoteFlags) {
|
|
132
|
-
return {
|
|
133
|
-
status: EXIT.infra,
|
|
134
|
-
output: `REMOTE_FLAG_NOT_PINNABLE: the remote feature-flag pin '${remoteFlags.spec}' (from --remote-flag and the wallet fixture's remoteFeatureFlags) cannot be applied to a verified release artifact; the artifact's manifest is signed evidence and is never rewritten.
|
|
135
|
-
Next: drop --remote-flag and remove remoteFeatureFlags from the wallet fixture to validate the artifact as shipped, or validate the variant on a source checkout launched without the artifact.`
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
140
|
return extensionLaunchReleaseArtifact(target, artifact);
|
|
139
141
|
}
|
|
140
142
|
return extensionLaunchDevelopment(target, remoteFlags);
|
package/dist/commands/logs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { adapterDetectNext, EXIT, flag, parseFlags,
|
|
1
|
+
import { adapterDetectNext, EXIT, flag, parseFlags, contextAdapter, spawnInherit, spawnScript, str, targetOf, usageOut } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { runnerDir } from "../paths.js";
|
|
@@ -8,7 +8,7 @@ async function handleLogs(argv) {
|
|
|
8
8
|
const { options } = parseFlags(argv, LOGS_BOOLEANS);
|
|
9
9
|
const json = flag(options, "json");
|
|
10
10
|
const target = targetOf(options);
|
|
11
|
-
const adapter =
|
|
11
|
+
const adapter = contextAdapter(target);
|
|
12
12
|
if (!adapter) {
|
|
13
13
|
return usageOut(json, "logs", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
|
|
14
14
|
}
|
package/dist/commands/prepare.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { acquireCheckoutLock, trackCheckoutChild, recordCommandStage, color, stripAnsi, harnessExecutable, recipeRuntimeDir,
|
|
1
|
+
import { acquireCheckoutLock, trackCheckoutChild, recordCommandStage, color, stripAnsi, harnessExecutable, recipeRuntimeDir, contextAdapter, optionFlag, optionString, parseArgs, targetPath, usageError, EXIT } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { OperationOutputTail } from "@farmslot/recipe-runner/runtime/operation";
|
|
4
4
|
import fs from "node:fs";
|
|
@@ -265,8 +265,8 @@ function mobilePlatformOption(value) {
|
|
|
265
265
|
Next: ${USAGE}`
|
|
266
266
|
);
|
|
267
267
|
}
|
|
268
|
-
function resolvePlatform(
|
|
269
|
-
const platform =
|
|
268
|
+
function resolvePlatform(target) {
|
|
269
|
+
const platform = contextAdapter(target);
|
|
270
270
|
const surface = platform && adapterRegistry.has(platform) ? getAdapterSurface(platform) : void 0;
|
|
271
271
|
if (surface?.prepare) {
|
|
272
272
|
return surface;
|
|
@@ -296,7 +296,7 @@ async function handlePrepareLocked(argv) {
|
|
|
296
296
|
const { options } = parseArgs(argv);
|
|
297
297
|
const json = optionFlag(options, "json");
|
|
298
298
|
const target = targetPath(options);
|
|
299
|
-
const surface = resolvePlatform(
|
|
299
|
+
const surface = resolvePlatform(target);
|
|
300
300
|
const platform = surface.id;
|
|
301
301
|
const artifactsDir = path.resolve(
|
|
302
302
|
optionString(options, "artifactsDir") ?? path.join(target, recipeRuntimeDir())
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { contextAdapter, adapterDetectNext, usageOut, applyWatcherPortOption, optionFlag, optionString, shellQuote, shellQuoteArg, targetPath } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import { assertAdapter } from "../paths.js";
|
|
3
3
|
import { getAdapterSurface } from "../adapters/surface.js";
|
|
4
4
|
async function handleProvision({ positional, options, rawArgv }) {
|
|
5
5
|
applyWatcherPortOption(options);
|
|
6
6
|
const json = optionFlag(options, "json");
|
|
7
7
|
const target = targetPath(options);
|
|
8
|
-
const adapter =
|
|
8
|
+
const adapter = contextAdapter(target);
|
|
9
9
|
if (!adapter) {
|
|
10
10
|
return usageOut(json, "provision", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
|
|
11
11
|
}
|
package/dist/commands/review.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { harnessContext, optionFlag, optionString, parseArgs, targetPath, usageError } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { runnerDir } from "../paths.js";
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
resolveReference,
|
|
16
16
|
defaultBaseRef
|
|
17
17
|
} from "../review/knowledge.js";
|
|
18
|
-
import "../adapters/surface.js";
|
|
19
18
|
const EXIT_OK = 0;
|
|
20
19
|
let cachedHarnessVersion;
|
|
21
20
|
function harnessVersion() {
|
|
@@ -25,18 +24,17 @@ function harnessVersion() {
|
|
|
25
24
|
}
|
|
26
25
|
return cachedHarnessVersion;
|
|
27
26
|
}
|
|
28
|
-
function adapterFromOptions(
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
function adapterFromOptions() {
|
|
28
|
+
const adapter = harnessContext()?.adapter;
|
|
29
|
+
const scope = REVIEW_ADAPTERS.find((id) => id === adapter?.value);
|
|
30
|
+
if (adapter?.source === "flag" && !scope) {
|
|
31
|
+
throw usageError(`--adapter must be one of ${REVIEW_ADAPTERS.join(", ")} (got ${adapter.value}).`);
|
|
33
32
|
}
|
|
34
|
-
|
|
35
|
-
return REVIEW_ADAPTERS.find((adapter) => adapter === detected) ?? "unscoped";
|
|
33
|
+
return scope ?? "unscoped";
|
|
36
34
|
}
|
|
37
35
|
function resolveReviewContext(options, { fetch = true } = {}) {
|
|
38
36
|
const target = targetPath(options);
|
|
39
|
-
const adapter = adapterFromOptions(
|
|
37
|
+
const adapter = adapterFromOptions();
|
|
40
38
|
const domain = optionString(options, "domain") ?? process.env.MM_HARNESS_DOMAIN;
|
|
41
39
|
const config = readConfig(configPath());
|
|
42
40
|
const context = { target, adapter, ...domain ? { domain } : {} };
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
writeMobileReleaseArtifactState
|
|
11
11
|
} from "../adapters/mobile/release-artifact-state.js";
|
|
12
12
|
import { extensionDepsBlock } from "./launch/extension.js";
|
|
13
|
+
import { recordExtensionConsoleLaunch } from "../adapters/extension/console-capture.js";
|
|
13
14
|
import { isExtensionDistStale } from "../adapters/extension/runtime-decision.js";
|
|
14
15
|
import { FeatureFlagSpecError, parseRemoteFlagSpec } from "../feature-flags.js";
|
|
15
16
|
async function handleRuntimeLaunch(args) {
|
|
@@ -186,6 +187,7 @@ async function handleRuntimeLaunchLocked({ options }) {
|
|
|
186
187
|
cdpPort
|
|
187
188
|
}));
|
|
188
189
|
}
|
|
190
|
+
recordExtensionConsoleLaunch(target);
|
|
189
191
|
const result = await spawnScriptStreaming(command[0], command.slice(1), target, {
|
|
190
192
|
forward: jsonMode ? "stderr" : "original",
|
|
191
193
|
stdin: jsonMode ? "ignore" : "inherit",
|
package/dist/commands/status.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { featureFlagReport } from "../feature-flags.js";
|
|
4
|
-
import { color,
|
|
4
|
+
import { color, contextAdapter, harnessContextField, adapterDetectNext, EXIT, usageOut, optionFlag, optionString, targetPath } from "@farmslot/recipe-cli/harness";
|
|
5
5
|
import { collectCheckoutView, renderCheckoutView } from "../checkout-view.js";
|
|
6
6
|
import { assertAdapter } from "../paths.js";
|
|
7
7
|
import { getAdapterSurface } from "../adapters/surface.js";
|
|
@@ -24,7 +24,7 @@ async function handleStatus({ options }) {
|
|
|
24
24
|
}
|
|
25
25
|
const fast = optionFlag(options, "fast");
|
|
26
26
|
const allDevices = optionFlag(options, "allDevices");
|
|
27
|
-
const adapter =
|
|
27
|
+
const adapter = contextAdapter(target);
|
|
28
28
|
if (!adapter) {
|
|
29
29
|
return usageOut(json, "status", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
|
|
30
30
|
}
|
|
@@ -58,6 +58,7 @@ async function handleStatus({ options }) {
|
|
|
58
58
|
command: "status",
|
|
59
59
|
adapter,
|
|
60
60
|
target,
|
|
61
|
+
...harnessContextField(),
|
|
61
62
|
view,
|
|
62
63
|
devices: liveView.devicesWithLive,
|
|
63
64
|
featureFlags: featureFlagReport(liveView.featureFlagOverrides),
|
|
@@ -79,6 +80,7 @@ async function handleStatus({ options }) {
|
|
|
79
80
|
command: "status",
|
|
80
81
|
adapter,
|
|
81
82
|
target,
|
|
83
|
+
...harnessContextField(),
|
|
82
84
|
view,
|
|
83
85
|
devices,
|
|
84
86
|
featureFlags: staticFeatureFlags,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { harnessExecutable,
|
|
1
|
+
import { harnessExecutable, contextAdapter, EXIT } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import { spawnSync } from "node:child_process";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
|
-
import "../adapters/surface.js";
|
|
5
4
|
const require2 = createRequire(import.meta.url);
|
|
6
5
|
const USAGE = "mm-harness task init <task-dir> --flow f --template id --title t [options]";
|
|
7
6
|
function hasOption(argv, name) {
|
|
@@ -14,7 +13,7 @@ function metamaskDefaults(argv) {
|
|
|
14
13
|
defaults.push("--mark-command", `${harnessExecutable()} checklist mark`);
|
|
15
14
|
}
|
|
16
15
|
if (!hasOption(argv, "--platform")) {
|
|
17
|
-
const adapter =
|
|
16
|
+
const adapter = contextAdapter(process.cwd());
|
|
18
17
|
if (adapter) defaults.push("--platform", adapter);
|
|
19
18
|
}
|
|
20
19
|
return defaults;
|
|
@@ -4,13 +4,14 @@ import {
|
|
|
4
4
|
consoleRecords,
|
|
5
5
|
libraryRootsFromEnv,
|
|
6
6
|
loadConsoleAllowlist,
|
|
7
|
-
messageSignature
|
|
7
|
+
messageSignature,
|
|
8
|
+
withBundledLibraryRoot
|
|
8
9
|
} from "../library/actions/shared/console-findings.mjs";
|
|
9
10
|
const consoleClassifier = {
|
|
10
11
|
records: (text) => consoleRecords(text),
|
|
11
12
|
classify: (record) => classifyConsoleRecord(record),
|
|
12
13
|
signature: (message) => messageSignature(message),
|
|
13
|
-
loadAllowlist: (libraryRoots) => loadConsoleAllowlist([...libraryRoots]),
|
|
14
|
+
loadAllowlist: (libraryRoots) => loadConsoleAllowlist(withBundledLibraryRoot([...libraryRoots])),
|
|
14
15
|
match: (event, allowlist) => allowlistMatch(event, allowlist),
|
|
15
16
|
libraryRoots: () => libraryRootsFromEnv()
|
|
16
17
|
};
|
package/dist/doctor.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { RECIPE_CLI_VERSION } from "@farmslot/recipe-cli";
|
|
4
|
-
import { color, harnessExecutable, recipeHarnessRoot, recipeRuntimeDir, readRuntimeContextField, resolveRuntimeContextPath } from "@farmslot/recipe-cli/harness";
|
|
4
|
+
import { color, harnessContext, harnessContextField, harnessExecutable, recipeHarnessRoot, recipeRuntimeDir, readRuntimeContextField, resolveRuntimeContextPath } from "@farmslot/recipe-cli/harness";
|
|
5
5
|
import { normalizeFeatureFlagRecord } from "./feature-flags.js";
|
|
6
6
|
import { getAdapterSurface } from "./adapters/surface.js";
|
|
7
7
|
import { isPin } from "./harness-pin.js";
|
|
@@ -107,10 +107,13 @@ function runtimeContextSummary(target, adapter) {
|
|
|
107
107
|
const file = envOverride ?? path.relative(target, contextPath);
|
|
108
108
|
const fields = {};
|
|
109
109
|
const specs = adapter ? RUNTIME_CONTEXT_FIELDS.filter((spec) => spec.adapters.includes(adapter)) : RUNTIME_CONTEXT_FIELDS;
|
|
110
|
+
const filled = new Set(
|
|
111
|
+
Object.values(harnessContext()?.ports ?? {}).flatMap((port) => port?.filled ? port.names ?? [] : [])
|
|
112
|
+
);
|
|
110
113
|
for (const spec of specs) {
|
|
111
114
|
const envName = spec.envVars.find((name) => {
|
|
112
115
|
const value = process.env[name];
|
|
113
|
-
return value !== void 0 && value !== "";
|
|
116
|
+
return value !== void 0 && value !== "" && !filled.has(name);
|
|
114
117
|
});
|
|
115
118
|
if (envName !== void 0) {
|
|
116
119
|
fields[spec.key] = { value: process.env[envName], source: "env", envVar: envName, customize: spec.customize };
|
|
@@ -165,6 +168,7 @@ function createDoctorReport(adapter, target, manifestValidation, actionManifestP
|
|
|
165
168
|
requiredChecks,
|
|
166
169
|
adapter,
|
|
167
170
|
target,
|
|
171
|
+
...harnessContextField(),
|
|
168
172
|
runner: runnerProvenance(actionManifestPath),
|
|
169
173
|
compatibilityMode: mode,
|
|
170
174
|
shape: repoShape(target),
|