@deeeed/metamask-harness 0.84.0 → 0.86.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 +65 -0
- package/README.md +5 -3
- package/adapters/extension/console-tail.mjs +11 -7
- package/adapters/extension/ensure-browser.sh +17 -18
- package/adapters/extension/refresh-build.sh +1 -1
- package/adapters/extension/start-watch.sh +17 -8
- package/adapters/manifest.json +1 -1
- package/adapters/mobile/reload-app.mjs +2 -1
- package/adapters/mobile/start-console-forwarder.sh +8 -0
- package/adapters/shared/resolve-slot-ports-core.mjs +48 -6
- package/dist/adapters/console-capture.js +3 -1
- 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 +3 -2
- 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 +32 -20
- 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-probe.js +8 -1
- 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 +16 -4
- package/dist/runner.js +18 -3
- package/docs/CONTRIBUTING.md +11 -0
- package/docs/QA.md +1 -0
- package/docs/RECIPES.md +18 -2
- package/docs/cli-contract.md +8 -6
- package/library/actions/core/perps/_controller.mjs +2 -2
- package/library/actions/extension/app/assert_no_console_errors.mjs +95 -0
- package/library/actions/extension/platform/cdp.mjs +72 -2
- package/library/actions/extension/ui/navigate.mjs +3 -1
- package/library/actions/extension/wallet/select_account.mjs +17 -17
- package/library/actions/extension/wallet/state.mjs +75 -21
- package/library/actions/mobile/app/assert_no_console_errors.mjs +129 -0
- package/library/actions/mobile/wallet/select_account.mjs +34 -18
- 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/core.action-manifest.json +6 -6
- package/library/manifests/extension.action-manifest.json +37 -1
- package/library/manifests/mobile.action-manifest.json +40 -4
- 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/scripts/completions.sh +2 -2
- package/site/assets/help-recipes.json +3 -2
|
@@ -4,7 +4,7 @@ import crypto from "node:crypto";
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { runnerDir } from "../../paths.js";
|
|
7
|
-
const USAGE = "Usage: mm-harness verify --adapter mobile -- [--target <metamask-mobile>] [--artifacts-dir <dir>] [--static-only] [--platform ios|android] [--preflight-mode fast|auto|default|rebuild-native|clean] [--no-auto-start]";
|
|
7
|
+
const USAGE = "Usage: mm-harness verify --adapter mobile -- [--target <metamask-mobile>] [--artifacts-dir <dir>] [--static-only] [--platform ios|android] [--watcher-port <port>] [--preflight-mode fast|auto|default|rebuild-native|clean] [--no-auto-start]";
|
|
8
8
|
const ENV_FILES = [".js.env", ".env", ".env.local"];
|
|
9
9
|
const PREFLIGHT_MODES = ["fast", "auto", "default", "rebuild-native", "clean"];
|
|
10
10
|
const AUTO_START_TRUE = ["1", "true", "TRUE", "True", "yes", "YES", "Yes", "on", "ON", "On"];
|
|
@@ -36,6 +36,7 @@ function parseMobileVerifyArgs(argv, env = process.env) {
|
|
|
36
36
|
let platform = env.RECIPE_HARNESS_PLATFORM || env.PLATFORM || "ios";
|
|
37
37
|
let preflightMode = env.RECIPE_HARNESS_MOBILE_PREFLIGHT_MODE || "fast";
|
|
38
38
|
let autoStart = env.RECIPE_HARNESS_MOBILE_AUTO_START ?? "false";
|
|
39
|
+
let watcherPort;
|
|
39
40
|
for (let i = 0; i < argv.length; i += 1) {
|
|
40
41
|
const arg = argv[i];
|
|
41
42
|
const needsValue = () => {
|
|
@@ -65,6 +66,12 @@ function parseMobileVerifyArgs(argv, env = process.env) {
|
|
|
65
66
|
platform = value;
|
|
66
67
|
break;
|
|
67
68
|
}
|
|
69
|
+
case "--watcher-port": {
|
|
70
|
+
const value = needsValue();
|
|
71
|
+
if (value === void 0) return { kind: "error", message: "Missing value for --watcher-port", exitCode: 2 };
|
|
72
|
+
watcherPort = value;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
68
75
|
case "--preflight-mode": {
|
|
69
76
|
const value = needsValue();
|
|
70
77
|
if (value === void 0) return { kind: "error", message: "Missing value for --preflight-mode", exitCode: 2 };
|
|
@@ -101,7 +108,8 @@ function parseMobileVerifyArgs(argv, env = process.env) {
|
|
|
101
108
|
staticOnly,
|
|
102
109
|
platform,
|
|
103
110
|
preflightMode,
|
|
104
|
-
autoStart: AUTO_START_TRUE.includes(autoStart)
|
|
111
|
+
autoStart: AUTO_START_TRUE.includes(autoStart),
|
|
112
|
+
...watcherPort === void 0 ? {} : { watcherPort }
|
|
105
113
|
}
|
|
106
114
|
};
|
|
107
115
|
}
|
|
@@ -141,8 +149,8 @@ function buildMobileVerifySummary(input) {
|
|
|
141
149
|
generatedAt: input.generatedAt
|
|
142
150
|
};
|
|
143
151
|
}
|
|
144
|
-
function resolveWatcherPort(target, env = process.env) {
|
|
145
|
-
const explicit = env.WATCHER_PORT || "";
|
|
152
|
+
function resolveWatcherPort(target, env = process.env, flag) {
|
|
153
|
+
const explicit = flag || env.RECIPE_WATCHER_PORT || env.WATCHER_PORT || "";
|
|
146
154
|
if (explicit) return explicit;
|
|
147
155
|
for (const file of ENV_FILES) {
|
|
148
156
|
const full = path.join(target, file);
|
|
@@ -299,7 +307,7 @@ async function runMobileVerify(argv, io = defaultIo) {
|
|
|
299
307
|
io.err(parsed.message);
|
|
300
308
|
return parsed.exitCode;
|
|
301
309
|
}
|
|
302
|
-
const { staticOnly, platform, preflightMode, autoStart } = parsed.options;
|
|
310
|
+
const { staticOnly, platform, preflightMode, autoStart, watcherPort } = parsed.options;
|
|
303
311
|
const target = path.resolve(parsed.options.target);
|
|
304
312
|
if (!fs.existsSync(target)) {
|
|
305
313
|
io.err(`Refusing mobile verify: target checkout does not exist: ${target}`);
|
|
@@ -344,9 +352,9 @@ async function runMobileVerify(argv, io = defaultIo) {
|
|
|
344
352
|
let fixtureStatus = null;
|
|
345
353
|
let portHolder = null;
|
|
346
354
|
if (!staticOnly) {
|
|
347
|
-
const port = resolveWatcherPort(target);
|
|
355
|
+
const port = resolveWatcherPort(target, process.env, watcherPort);
|
|
348
356
|
if (!isNumericWatcherPort(port)) {
|
|
349
|
-
io.err(`Refusing mobile verify: resolved watcher port is not numeric: '${port}' (check WATCHER_PORT)`);
|
|
357
|
+
io.err(`Refusing mobile verify: resolved watcher port is not numeric: '${port}' (check --watcher-port, RECIPE_WATCHER_PORT or WATCHER_PORT)`);
|
|
350
358
|
return 2;
|
|
351
359
|
}
|
|
352
360
|
let deviceTarget = mobileDeviceTarget(target, platform, process.env);
|
|
@@ -9,7 +9,7 @@ const webDappActions = {
|
|
|
9
9
|
"app.performance_assert"
|
|
10
10
|
],
|
|
11
11
|
cdpTarget: { transport: "chrome-cdp", probePath: "json/version" },
|
|
12
|
-
ui: (harness
|
|
12
|
+
ui: (harness) => ({
|
|
13
13
|
base: harness.createCdpWebUiTransport({
|
|
14
14
|
async withPage(input, callback) {
|
|
15
15
|
const { withAppPage } = await import("../../../library/actions/web-dapp/platform/page.mjs");
|
|
@@ -30,14 +30,16 @@ const webDappActions = {
|
|
|
30
30
|
async execute(action, node, context, standard) {
|
|
31
31
|
if (action === "app.hud") {
|
|
32
32
|
const { showAppHud } = await import("../../../library/actions/web-dapp/platform/hud.mjs");
|
|
33
|
-
return showAppHud(
|
|
34
|
-
{ action, node, context: { nodeId: context.nodeId, projectRoot: context.projectRoot } },
|
|
35
|
-
{ hudPolicy }
|
|
36
|
-
);
|
|
33
|
+
return showAppHud({ action, node, context: { nodeId: context.nodeId, projectRoot: context.projectRoot } });
|
|
37
34
|
}
|
|
38
35
|
return standard();
|
|
39
36
|
}
|
|
40
37
|
}),
|
|
38
|
+
// Deletes hud.json (the wallet host redraws from it) and the HUD on the app tabs.
|
|
39
|
+
async clearHud(projectRoot) {
|
|
40
|
+
const { showAppHud } = await import("../../../library/actions/web-dapp/platform/hud.mjs");
|
|
41
|
+
await showAppHud({ node: { clear: true }, context: { nodeId: "hud-clear", projectRoot } });
|
|
42
|
+
},
|
|
41
43
|
// ensure_positions and ensure_orders with an open or present state place an order.
|
|
42
44
|
inputFindings: (nodeId, node) => perpsOrderInputFindings(nodeId, node, { ensureChecksOnly: false })
|
|
43
45
|
};
|
package/dist/adapters.js
CHANGED
|
@@ -90,7 +90,9 @@ const LIVE_ONLY_APP_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
90
90
|
"app.network_capture",
|
|
91
91
|
"app.network_assert",
|
|
92
92
|
"app.performance_capture",
|
|
93
|
-
"app.performance_assert"
|
|
93
|
+
"app.performance_assert",
|
|
94
|
+
// Proves a capture of the running app; a static result would pass on no evidence.
|
|
95
|
+
"metamask.app.assert_no_console_errors"
|
|
94
96
|
]);
|
|
95
97
|
function requiresLiveAdapter(platform, action) {
|
|
96
98
|
return LIVE_ONLY_ACTIONS.has(action) || Boolean(getAdapterSurface(platform).actions.liveOnly?.includes(action)) || LIVE_ONLY_WALLET_ACTIONS.has(action) || LIVE_ONLY_FEATURE_FLAG_ACTIONS.has(action) || LIVE_ONLY_APP_ACTIONS.has(action);
|
|
@@ -290,7 +292,7 @@ function createMetaMaskSemanticAdapters(platform, declaredCustomActions = [], pr
|
|
|
290
292
|
)
|
|
291
293
|
);
|
|
292
294
|
}
|
|
293
|
-
function createMetaMaskUiTransport(platform, harness, preparedLiveAdapters
|
|
295
|
+
function createMetaMaskUiTransport(platform, harness, preparedLiveAdapters) {
|
|
294
296
|
const ui = getAdapterSurface(platform).actions.ui;
|
|
295
297
|
if (!ui) {
|
|
296
298
|
return {
|
|
@@ -301,7 +303,7 @@ function createMetaMaskUiTransport(platform, harness, preparedLiveAdapters, { hu
|
|
|
301
303
|
}
|
|
302
304
|
};
|
|
303
305
|
}
|
|
304
|
-
const { base, execute } = ui(harness, { hudPolicy });
|
|
306
|
+
const { base, execute } = ui(harness, { hudPolicy: "show" });
|
|
305
307
|
async function standard(action, node, context) {
|
|
306
308
|
if (action === "ui.navigate") {
|
|
307
309
|
const live = await runLiveFirst(
|
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,19 +714,21 @@ 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>)
|
|
714
721
|
--action-manifest <path> Override the action manifest
|
|
715
722
|
--library <name=path> Add/override a recipe-library source (repeatable)
|
|
716
723
|
--heal <off|infra-only|auto> Healing policy (default: infra-only); auto-ensures the overlay
|
|
724
|
+
--hud <show|hide> Recipe HUD: the call's intent= drawn over the app, headless included (default: show)
|
|
717
725
|
--json Machine-readable output
|
|
718
726
|
|
|
719
727
|
Example (real actions; run mm-harness actions for this checkout's full set):
|
|
720
728
|
mm-harness call ensure_unlocked --adapter extension # a wallet action (extension/mobile)
|
|
721
729
|
mm-harness call navigate page=perps --adapter mobile
|
|
722
730
|
mm-harness call command cmd="echo hi" --adapter core # the universal action (all adapters)
|
|
731
|
+
mm-harness call ui.screenshot intent="Show the order filled" # intent= is the HUD text
|
|
723
732
|
|
|
724
733
|
Remote feature flags (mobile applies at runtime; extension pins at launch):
|
|
725
734
|
mm-harness call metamask.feature_flags.read --adapter mobile
|
|
@@ -731,7 +740,8 @@ Remote feature flags (mobile applies at runtime; extension pins at launch):
|
|
|
731
740
|
"--list": bool(),
|
|
732
741
|
"--domain": value(),
|
|
733
742
|
"--source": value(),
|
|
734
|
-
"--sort": value(["domain", "name", "library"])
|
|
743
|
+
"--sort": value(["domain", "name", "library"]),
|
|
744
|
+
"--hud": value(["show", "hide"])
|
|
735
745
|
}),
|
|
736
746
|
positionals: [{ label: "action" }],
|
|
737
747
|
minimumPositionals: 0,
|
|
@@ -765,7 +775,7 @@ Discovery:
|
|
|
765
775
|
|
|
766
776
|
Common overrides:
|
|
767
777
|
--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 <
|
|
778
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
769
779
|
--platform <ios|android> Mobile platform preference; use --adapter for the product adapter
|
|
770
780
|
--target <path> Checkout path (default: cwd)
|
|
771
781
|
--artifacts-dir <dir> Override evidence output (default: active task/artifacts, otherwise a checkout-local temp/recipe/runs/<run>)
|
|
@@ -778,7 +788,7 @@ Common overrides:
|
|
|
778
788
|
--json Machine-readable output
|
|
779
789
|
--json-stream Line-flushed JSONL progress + terminal event
|
|
780
790
|
--record-video=full-run Record a video of the run
|
|
781
|
-
--hud <
|
|
791
|
+
--hud <show|hide> Recipe HUD: each node's intent drawn over the app on every adapter, headless included (default: show)
|
|
782
792
|
|
|
783
793
|
Advanced integrations:
|
|
784
794
|
runtime: --cdp-port, --watcher-port, --runtime-dir, --slot,
|
|
@@ -801,7 +811,7 @@ Example:
|
|
|
801
811
|
"--plan": bool(),
|
|
802
812
|
"--proof": bool(),
|
|
803
813
|
"--describe": bool(),
|
|
804
|
-
"--hud": value(["
|
|
814
|
+
"--hud": value(["show", "hide"])
|
|
805
815
|
}),
|
|
806
816
|
positionals: [{ label: "recipe" }],
|
|
807
817
|
minimumPositionals: 1,
|
|
@@ -850,7 +860,7 @@ Example:
|
|
|
850
860
|
--cdp-port <port> Extension CDP port for the liveness probe (env: CDP_PORT / RECIPE_CDP_PORT)
|
|
851
861
|
--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
862
|
--all-devices Mobile only: show every connected device instead of the slot-scoped target
|
|
853
|
-
--adapter <
|
|
863
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
854
864
|
--target <path> Checkout path (default: cwd)
|
|
855
865
|
--runtime-dir <dir> Runtime dir containing agentic-runtime.json (relative to target)
|
|
856
866
|
--json Machine-readable output (incompatible with --print-ready)
|
|
@@ -882,7 +892,7 @@ Example:
|
|
|
882
892
|
when available. Does not launch an app or run a recipe.
|
|
883
893
|
|
|
884
894
|
--target <path> Checkout path (default: cwd)
|
|
885
|
-
--adapter <
|
|
895
|
+
--adapter <{adapters}> Adapter label (auto-detected when possible)
|
|
886
896
|
--base <ref> Diff base (default: PR base, then remote HEAD, then repo fallback)
|
|
887
897
|
--profile <fast|full> Validation depth (default: fast)
|
|
888
898
|
--fix Fix changed files, then validate them
|
|
@@ -929,11 +939,11 @@ Example:
|
|
|
929
939
|
Optional advice:
|
|
930
940
|
advisor-status --json
|
|
931
941
|
Resolve saved settings and overrides without reading tasks or calling a model.
|
|
932
|
-
plan --task <task.json> --adapter <
|
|
942
|
+
plan --task <task.json> --adapter <{adapters}> --advisor typesafe
|
|
933
943
|
Assess each acceptance criterion before a recipe exists. Task JSON contains
|
|
934
944
|
acceptanceCriteria: ["criterion", "..."] (1\u201320 entries), with optional title/description.
|
|
935
945
|
Returns known candidate refs for reuse/composition, or an explicit discovery gap.
|
|
936
|
-
advise --recipe <recipe.json> --task <TASK.md> --adapter <
|
|
946
|
+
advise --recipe <recipe.json> --task <TASK.md> --adapter <{adapters}>
|
|
937
947
|
--advisor <provider|off> Override saved policy for this task (currently: typesafe)
|
|
938
948
|
--advisor-model <model> Override the provider default model or alias
|
|
939
949
|
--advisor-stages <csv> Select plan,draft,evidence (saved/default: plan)
|
|
@@ -983,7 +993,7 @@ Example:
|
|
|
983
993
|
provisioning path only: artifact cache + simulator create + simctl install.
|
|
984
994
|
JavaScript dependencies and Metro remain dispatch-time launch concerns.
|
|
985
995
|
|
|
986
|
-
--adapter <
|
|
996
|
+
--adapter <{adapters}> Target adapter (mobile supported; the others teach)
|
|
987
997
|
--target <path> Slot checkout path (default: cwd)
|
|
988
998
|
--platform <ios> Platform (default ios)
|
|
989
999
|
--simulator <name|udid> Override agentic-runtime.json simulator (alias: --device)
|
|
@@ -1027,7 +1037,7 @@ Example:
|
|
|
1027
1037
|
artifact cache + simulator create + simctl install. JavaScript dependencies
|
|
1028
1038
|
and Metro remain dispatch-time launch concerns.
|
|
1029
1039
|
|
|
1030
|
-
--adapter <
|
|
1040
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
1031
1041
|
--target <path> Checkout path (default: cwd)
|
|
1032
1042
|
--runway Thin mobile Runway artifact install instead of overlay install
|
|
1033
1043
|
--platform <ios> Runway platform (default ios)
|
|
@@ -1062,7 +1072,7 @@ Example:
|
|
|
1062
1072
|
Extension live checks infer the checkout CDP port from runtime context,
|
|
1063
1073
|
pool, or slot suffix when --cdp-port is omitted.
|
|
1064
1074
|
|
|
1065
|
-
--adapter <
|
|
1075
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
1066
1076
|
--target <path> Checkout path (default: cwd)
|
|
1067
1077
|
--json Machine-readable output
|
|
1068
1078
|
|
|
@@ -1082,7 +1092,7 @@ Example:
|
|
|
1082
1092
|
|
|
1083
1093
|
Remove the installed overlay and restore the checkout.
|
|
1084
1094
|
|
|
1085
|
-
--adapter <
|
|
1095
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
1086
1096
|
--target <path> Checkout path (default: cwd)
|
|
1087
1097
|
|
|
1088
1098
|
Example:
|
|
@@ -1235,7 +1245,7 @@ Example:
|
|
|
1235
1245
|
--source <label> Log source per adapter \u2014 mobile: metro|app;
|
|
1236
1246
|
extension: extension|dapp|webpack|watcher|rebuild.
|
|
1237
1247
|
Core is headless (teaching error).
|
|
1238
|
-
--adapter <
|
|
1248
|
+
--adapter <{adapters}> Target adapter (auto-detected inside a checkout)
|
|
1239
1249
|
--target <path> Checkout path (default: cwd)
|
|
1240
1250
|
--json Machine-readable output
|
|
1241
1251
|
|
|
@@ -1458,5 +1468,7 @@ export {
|
|
|
1458
1468
|
HIDDEN_COMMANDS,
|
|
1459
1469
|
PUBLIC_COMMANDS,
|
|
1460
1470
|
REPLACED_OPTIONS,
|
|
1461
|
-
explainMissingAdapterLibrary
|
|
1471
|
+
explainMissingAdapterLibrary,
|
|
1472
|
+
selectableAdapters,
|
|
1473
|
+
withAdapterList
|
|
1462
1474
|
};
|
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 } : {} };
|