@deeeed/metamask-harness 0.80.0 → 0.82.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 +43 -0
- package/adapters/manifest.json +48 -64
- package/adapters/{terminal → web-dapp}/cleanup.mjs +9 -9
- package/adapters/{terminal → web-dapp}/inject.mjs +14 -14
- package/adapters/{terminal → web-dapp}/launch.mjs +27 -24
- package/adapters/web-dapp/lib/blocked-hosts.mjs +24 -0
- package/adapters/{terminal → web-dapp}/lib/cdp-client.mjs +1 -1
- package/adapters/{terminal → web-dapp}/lib/display.mjs +1 -1
- package/adapters/{terminal → web-dapp}/lib/hud.mjs +1 -1
- package/adapters/web-dapp/lib/policy.mjs +79 -0
- package/adapters/{terminal → web-dapp}/lib/processes.mjs +8 -8
- package/adapters/{terminal → web-dapp}/lib/readiness.mjs +32 -34
- package/adapters/{terminal → web-dapp}/stop.mjs +5 -4
- package/adapters/{terminal → web-dapp}/verify.mjs +9 -6
- package/adapters/{terminal → web-dapp}/wallet-host.mjs +44 -227
- package/dist/adapters/core/actions.js +4 -1
- package/dist/adapters/extension/actions.js +6 -2
- package/dist/adapters/extension/network-observer.js +13 -0
- package/dist/adapters/extension/run.js +115 -31
- package/dist/adapters/mobile/actions.js +4 -1
- package/dist/adapters/mobile/network-observer.js +68 -0
- package/dist/adapters/mobile/performance-observer.js +1 -3
- package/dist/adapters/mobile/run.js +32 -9
- package/dist/adapters/perps-order-inputs.js +36 -0
- package/dist/adapters/plugin-surface.js +98 -0
- package/dist/adapters/proof-failure.js +11 -0
- package/dist/adapters/surface.js +1 -1
- package/dist/adapters/{terminal → web-dapp}/actions.js +11 -8
- package/dist/adapters/web-dapp/console-capture.js +63 -0
- package/dist/adapters/web-dapp/doctor-checks.js +33 -0
- package/dist/adapters/{terminal → web-dapp}/launch.js +21 -19
- package/dist/adapters/web-dapp/overlay.js +21 -0
- package/dist/adapters/web-dapp/readiness.js +10 -0
- package/dist/adapters/{terminal → web-dapp}/run.js +22 -17
- package/dist/adapters/{terminal → web-dapp}/stop.js +5 -4
- package/dist/adapters/web-dapp/surface.js +149 -0
- package/dist/adapters.js +20 -4
- package/dist/cli.js +34 -6
- package/dist/command-contract.js +29 -7
- package/dist/commands/check.js +32 -8
- package/dist/commands/completion-candidates.js +5 -5
- package/dist/commands/doctor.js +19 -2
- package/dist/commands/farmslot-ready.js +1 -0
- package/dist/commands/help.js +1 -1
- package/dist/commands/launch/device.js +5 -5
- package/dist/commands/self-test.js +10 -5
- package/dist/engine.js +47 -0
- package/dist/funding-execution-context.js +81 -0
- package/dist/manifest.js +48 -24
- package/dist/mm-harness-cli.js +20 -3
- package/dist/performance-observation.js +7 -15
- package/dist/recipe-assistance-context.js +6 -7
- package/dist/runner.js +28 -8
- package/docs/CONTRIBUTING.md +4 -2
- package/docs/RECIPES.md +31 -3
- package/docs/cli-contract.md +5 -3
- package/library/actions/core/perps/_controller.mjs +24 -28
- package/library/actions/core/perps/_rewards.mjs +186 -0
- package/library/actions/core/perps/close_positions.mjs +1 -1
- package/library/actions/core/perps/place_order.mjs +167 -45
- package/library/actions/core/perps/quote_fees.mjs +7 -4
- package/library/actions/core/wallet/list_accounts.mjs +1 -1
- package/library/actions/extension/perps/close_visible_position.mjs +5 -0
- package/library/actions/extension/perps/edit_margin.mjs +4 -0
- package/library/actions/extension/perps/mutation-receipt.mjs +95 -3
- package/library/actions/extension/perps/perps.mjs +320 -3
- package/library/actions/extension/perps/place_order.mjs +3 -1
- package/library/actions/extension/perps/update_position_tpsl.mjs +4 -0
- package/library/actions/extension/platform/cdp.mjs +71 -3
- package/library/actions/mobile/perps/perps.mjs +216 -11
- package/library/actions/mobile/perps/place_order.mjs +3 -1
- package/library/actions/shared/console-collector.mjs +1 -1
- package/library/actions/shared/perps/order-policy.mjs +177 -0
- package/library/actions/{core/wallet/_fixture-accounts.mjs → shared/wallet/fixture-accounts.mjs} +18 -3
- package/library/actions/{terminal → web-dapp}/app/assert_no_console_errors.mjs +4 -4
- package/library/actions/{terminal → web-dapp}/app/launch.mjs +8 -7
- package/library/actions/{terminal → web-dapp}/platform/hud.mjs +7 -6
- package/library/actions/{terminal → web-dapp}/platform/page.mjs +13 -12
- package/library/actions/{terminal → web-dapp}/platform/runtime.mjs +16 -12
- package/library/actions/web-dapp/ui/navigate.mjs +24 -0
- package/library/actions/web-dapp/wallet/_signature-log.mjs +32 -0
- package/library/actions/{terminal → web-dapp}/wallet/assert_signatures.mjs +8 -14
- package/library/actions/{terminal → web-dapp}/wallet/list_accounts.mjs +2 -2
- package/library/actions/web-dapp/wallet/read_signatures.mjs +38 -0
- package/library/manifests/core.action-manifest.json +6 -2
- package/library/manifests/extension.action-manifest.json +4 -0
- package/library/manifests/mobile.action-manifest.json +12 -0
- package/library/manifests/{terminal.action-manifest.json → web-dapp.action-manifest.json} +18 -702
- package/package.json +6 -6
- package/site/assets/help-recipes.json +1 -0
- package/adapters/terminal/lib/mainnet-guard.mjs +0 -177
- package/adapters/terminal/lib/origin.mjs +0 -30
- package/adapters/terminal/lib/page-script.mjs +0 -246
- package/adapters/terminal/lib/strict-wallet.mjs +0 -138
- package/dist/adapters/terminal/console-capture.js +0 -59
- package/dist/adapters/terminal/doctor-checks.js +0 -22
- package/dist/adapters/terminal/overlay.js +0 -18
- package/dist/adapters/terminal/readiness.js +0 -11
- package/dist/adapters/terminal/surface.js +0 -133
- package/dist/commands/call.js +0 -671
- package/dist/commands/list-executables.js +0 -245
- package/dist/commands/manifest.js +0 -477
- package/dist/commands/run-engine.js +0 -1301
- package/dist/commands/run.js +0 -730
- package/dist/discovery.js +0 -15
- package/dist/metamask-action-validation.js +0 -68
- package/dist/network-observation.js +0 -290
- package/library/actions/terminal/perps/_venue.mjs +0 -242
- package/library/actions/terminal/perps/assert_orders.mjs +0 -54
- package/library/actions/terminal/perps/assert_positions.mjs +0 -40
- package/library/actions/terminal/perps/read_orders.mjs +0 -26
- package/library/actions/terminal/perps/read_positions.mjs +0 -25
- package/library/actions/terminal/perps/read_snapshot.mjs +0 -40
- package/library/actions/terminal/perps/revoke_agent.mjs +0 -58
- package/library/actions/terminal/perps/teardown_state.mjs +0 -104
- package/library/actions/terminal/ui/navigate.mjs +0 -31
- package/library/actions/terminal/wallet/_signature-log.mjs +0 -177
- package/library/actions/terminal/wallet/read_signatures.mjs +0 -37
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { runnerDir } from "../../paths.js";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { webDappAdapterId } from "../../../adapters/web-dapp/lib/policy.mjs";
|
|
5
|
+
function stopWebDappBrowserSync(target) {
|
|
6
|
+
const args = [path.join(runnerDir, "adapters", "web-dapp", "stop.mjs"), "--target", path.resolve(target)];
|
|
6
7
|
const cdpPort = process.env.RECIPE_CDP_PORT ?? process.env.CDP_PORT;
|
|
7
8
|
if (cdpPort) args.push("--cdp-port", cdpPort);
|
|
8
9
|
const result = spawnSync(process.execPath, args, { encoding: "utf8" });
|
|
@@ -10,10 +11,10 @@ function stopTerminalBrowserSync(target) {
|
|
|
10
11
|
const status = result.status ?? 1;
|
|
11
12
|
return {
|
|
12
13
|
status,
|
|
13
|
-
summary: status === 0 ?
|
|
14
|
+
summary: status === 0 ? `${webDappAdapterId()} browser and wallet host stopped` : `${webDappAdapterId()} browser stop failed`,
|
|
14
15
|
output
|
|
15
16
|
};
|
|
16
17
|
}
|
|
17
18
|
export {
|
|
18
|
-
|
|
19
|
+
stopWebDappBrowserSync
|
|
19
20
|
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { shellQuote } from "@farmslot/recipe-cli/harness";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { defineAdapter } from "@farmslot/adapter-sdk";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import { POLICY_ENV, webDappAdapterId, webDappPolicy } from "../../../adapters/web-dapp/lib/policy.mjs";
|
|
6
|
+
import { WEB_DAPP_CONSOLE_FILES, webDappRuntimeFile } from "./console-capture.js";
|
|
7
|
+
import { stopWebDappBrowserSync } from "./stop.js";
|
|
8
|
+
import { adapterRegistry } from "../registry.js";
|
|
9
|
+
import { webDappActions } from "./actions.js";
|
|
10
|
+
import { webDappHarness, webDappRuntimeContext } from "./overlay.js";
|
|
11
|
+
import { webDappReadiness } from "./readiness.js";
|
|
12
|
+
import { webDappDiagnostics, webDappObservation } from "./run.js";
|
|
13
|
+
function portFromEnv(...names) {
|
|
14
|
+
for (const name of names) {
|
|
15
|
+
const raw = process.env[name];
|
|
16
|
+
if (raw && /^\d+$/u.test(raw)) return Number(raw);
|
|
17
|
+
}
|
|
18
|
+
return void 0;
|
|
19
|
+
}
|
|
20
|
+
function webDappAppPort() {
|
|
21
|
+
return portFromEnv("TERMINAL_APP_PORT", "RECIPE_WATCHER_PORT", "WATCHER_PORT");
|
|
22
|
+
}
|
|
23
|
+
function webDappCdpPort() {
|
|
24
|
+
return portFromEnv("RECIPE_CDP_PORT", "CDP_PORT");
|
|
25
|
+
}
|
|
26
|
+
function webDappSignerFor(target) {
|
|
27
|
+
try {
|
|
28
|
+
const state = JSON.parse(fs.readFileSync(webDappRuntimeFile(target, "browser.json"), "utf8"));
|
|
29
|
+
if (typeof state.signer === "string") return state.signer;
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
return process.env.TERMINAL_SIGNER || "extension";
|
|
33
|
+
}
|
|
34
|
+
function bindWebDappPolicy(adapter) {
|
|
35
|
+
if (adapter.extends === "web-dapp" && typeof adapter.policy?.module === "string") {
|
|
36
|
+
process.env[POLICY_ENV] = adapter.policy.module;
|
|
37
|
+
}
|
|
38
|
+
return adapter;
|
|
39
|
+
}
|
|
40
|
+
const webDappSurface = defineAdapter({
|
|
41
|
+
id: "web-dapp",
|
|
42
|
+
sdkVersion: 1,
|
|
43
|
+
headless: false,
|
|
44
|
+
resolveSlotPorts() {
|
|
45
|
+
},
|
|
46
|
+
async runtimeStatus(target) {
|
|
47
|
+
if (!process.env[POLICY_ENV]) {
|
|
48
|
+
return {
|
|
49
|
+
decision: "blocked",
|
|
50
|
+
reasonCode: "web-dapp-venue-policy",
|
|
51
|
+
reasons: ["web-dapp needs a venue policy: select an adapter that extends it"],
|
|
52
|
+
nextAction: "pass --adapter <the adapter that extends web-dapp>, e.g. --adapter terminal, with its recipe library on RECIPE_LIBRARY_PATH",
|
|
53
|
+
deps: "missing",
|
|
54
|
+
devServer: { label: "next", status: "down" }
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const policy = webDappPolicy();
|
|
58
|
+
const { webDappReadiness: webDappReadiness2 } = await import("../../../adapters/web-dapp/lib/readiness.mjs");
|
|
59
|
+
const report = await webDappReadiness2({
|
|
60
|
+
policy,
|
|
61
|
+
target: path.resolve(target),
|
|
62
|
+
appPort: webDappAppPort(),
|
|
63
|
+
cdpPort: webDappCdpPort(),
|
|
64
|
+
signer: process.env.TERMINAL_SIGNER || "extension"
|
|
65
|
+
});
|
|
66
|
+
const blocking = report.checks.filter((check) => check.required && check.status === "fail");
|
|
67
|
+
const devServer = report.checks.find((check) => check.id === "app-dev-server");
|
|
68
|
+
return {
|
|
69
|
+
decision: blocking.length === 0 ? "ready" : "blocked",
|
|
70
|
+
reasonCode: blocking[0]?.id,
|
|
71
|
+
reasons: (blocking.length ? blocking : report.checks).map((check) => `${check.id}: ${check.detail}`),
|
|
72
|
+
nextAction: blocking.length === 0 ? void 0 : blocking[0].id === "app-dev-server" || blocking[0].id === "testnet-forced" ? "start the slot dev server with testnet forced (Farmslot preflight), then retry" : `mm-harness doctor --adapter ${policy.adapterId} --target ${shellQuote(path.resolve(target))} --json`,
|
|
73
|
+
deps: report.checks.find((check) => check.id === "dependencies")?.status === "pass" ? "current" : "missing",
|
|
74
|
+
devServer: {
|
|
75
|
+
label: "next",
|
|
76
|
+
status: devServer?.status === "pass" ? "up" : "down"
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
},
|
|
80
|
+
runwayProvision: {
|
|
81
|
+
async run(target, options) {
|
|
82
|
+
return {
|
|
83
|
+
schemaVersion: 1,
|
|
84
|
+
command: "provision",
|
|
85
|
+
adapter: webDappAdapterId(),
|
|
86
|
+
target: path.resolve(target),
|
|
87
|
+
status: "fail",
|
|
88
|
+
exitCode: 2,
|
|
89
|
+
error: {
|
|
90
|
+
code: "UNSUPPORTED_ADAPTER",
|
|
91
|
+
message: `the ${process.env[POLICY_ENV] ? webDappPolicy().checkout.name : "web dapp"} is a website; there is no simulator or build to provision.`,
|
|
92
|
+
userAction: options.rerunCommand || `mm-harness launch --adapter ${webDappAdapterId()}`
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
devServer: {
|
|
98
|
+
label: "browser",
|
|
99
|
+
describe: () => `${webDappAdapterId()} slot browser and wallet host (the Next.js dev server belongs to the slot)`,
|
|
100
|
+
stop(target) {
|
|
101
|
+
const result = stopWebDappBrowserSync(target);
|
|
102
|
+
return { kind: "stopped", status: result.status, summary: result.summary, output: result.output };
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
logSources(target) {
|
|
106
|
+
return [
|
|
107
|
+
{ label: "app-console", path: webDappRuntimeFile(target, WEB_DAPP_CONSOLE_FILES.app) },
|
|
108
|
+
...webDappSignerFor(target) === "extension" ? [{ label: "extension-console", path: webDappRuntimeFile(target, WEB_DAPP_CONSOLE_FILES.extension) }] : [],
|
|
109
|
+
{ label: "wallet-requests", path: webDappRuntimeFile(target, "wallet-requests.jsonl") },
|
|
110
|
+
{ label: "wallet-host", path: webDappRuntimeFile(target, "wallet-host.log") },
|
|
111
|
+
{ label: "browser", path: webDappRuntimeFile(target, "browser.log") },
|
|
112
|
+
{ label: "next", path: path.join(target, "temp/farmslot/next-dev.log") }
|
|
113
|
+
];
|
|
114
|
+
},
|
|
115
|
+
// The app page's console and uncaught exceptions, as the Extension's
|
|
116
|
+
// diagnostics read the extension console: errors make a run REVIEW.
|
|
117
|
+
appLogSource(target) {
|
|
118
|
+
return { label: "app-console", path: webDappRuntimeFile(target, WEB_DAPP_CONSOLE_FILES.app) };
|
|
119
|
+
},
|
|
120
|
+
flags: { launch: ["freshProfile", "headless", "headful"] },
|
|
121
|
+
hints: {
|
|
122
|
+
// Bare web-dapp has no venue: every hint names the adapter that extends it.
|
|
123
|
+
launch: "pass --adapter <the adapter that extends web-dapp>, e.g. --adapter terminal, with its recipe library on RECIPE_LIBRARY_PATH",
|
|
124
|
+
relaunch: "pass --adapter <the adapter that extends web-dapp>, e.g. --adapter terminal, with --fresh-profile",
|
|
125
|
+
runtimeProbeRecovery: () => "pass --adapter <the adapter that extends web-dapp>, e.g. --adapter terminal, with its recipe library on RECIPE_LIBRARY_PATH"
|
|
126
|
+
},
|
|
127
|
+
launch: async (context) => (await import("./launch.js")).launchWebDapp(context),
|
|
128
|
+
actions: webDappActions,
|
|
129
|
+
harness: webDappHarness,
|
|
130
|
+
runtimeContext: webDappRuntimeContext,
|
|
131
|
+
readiness: webDappReadiness,
|
|
132
|
+
fixtures: { operations: ["init", "sync", "set"] },
|
|
133
|
+
debug: {
|
|
134
|
+
args: ({ devMenu }) => [
|
|
135
|
+
...process.env.WATCHER_PORT ? ["--port", process.env.WATCHER_PORT] : [],
|
|
136
|
+
"--action",
|
|
137
|
+
devMenu ? "dev-menu" : "debug"
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
diagnostics: webDappDiagnostics,
|
|
141
|
+
observation: webDappObservation
|
|
142
|
+
});
|
|
143
|
+
adapterRegistry.register(webDappSurface);
|
|
144
|
+
export {
|
|
145
|
+
bindWebDappPolicy,
|
|
146
|
+
webDappAppPort,
|
|
147
|
+
webDappCdpPort,
|
|
148
|
+
webDappSurface
|
|
149
|
+
};
|
package/dist/adapters.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import http from "node:http";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { compatibilityMode, fixtureSummary, repoShape } from "./doctor.js";
|
|
4
|
-
import { runLiveAdapterScript } from "@farmslot/recipe-cli/harness";
|
|
4
|
+
import { liveAdapterProcessTimeoutMs, runLiveAdapterScript, runNetworkCaptureAction } from "@farmslot/recipe-cli/harness";
|
|
5
5
|
import { trustedMutationContextExtras } from "./funding-execution-context.js";
|
|
6
6
|
import { LIBRARY_ACTION_NAMESPACE } from "./paths.js";
|
|
7
7
|
import { liveTsxCandidates } from "./live-tsx.js";
|
|
8
8
|
import { resolveWalletImportCredentials, validateWalletImportOptions } from "../library/actions/shared/wallet/import-source.mjs";
|
|
9
9
|
import { isRecord, traceText } from "./action-values.js";
|
|
10
10
|
import { getAdapterSurface } from "./adapters/surface.js";
|
|
11
|
-
import { handleRunNetworkAction } from "./network-observation.js";
|
|
12
11
|
import { handleRunPerformanceAction } from "./performance-observation.js";
|
|
13
12
|
function simpleAdapter(action, executor) {
|
|
14
13
|
return {
|
|
@@ -100,6 +99,12 @@ function liveRuntimeConfigured(platform, node) {
|
|
|
100
99
|
if (!getAdapterSurface(platform).actions.liveNeedsCdpPort) return true;
|
|
101
100
|
return Boolean(node.cdp_port ?? process.env.CDP_PORT ?? process.env.RECIPE_CDP_PORT);
|
|
102
101
|
}
|
|
102
|
+
const IMMEDIATE_CLOSE_ALLOWANCE_MS = 18e4;
|
|
103
|
+
function withImmediateCloseBudget(action, node) {
|
|
104
|
+
if (action !== `${LIBRARY_ACTION_NAMESPACE}.perps.place_order`) return node;
|
|
105
|
+
if (node.close_immediately !== true && node.closeImmediately !== true) return node;
|
|
106
|
+
return { ...node, live_adapter_timeout_ms: liveAdapterProcessTimeoutMs(node) + IMMEDIATE_CLOSE_ALLOWANCE_MS };
|
|
107
|
+
}
|
|
103
108
|
async function runLiveFirst(platform, action, node, context, forceLive = false, preparedLiveAdapters) {
|
|
104
109
|
if (node.allow_static_placeholder === true) {
|
|
105
110
|
throw new Error(
|
|
@@ -111,7 +116,7 @@ async function runLiveFirst(platform, action, node, context, forceLive = false,
|
|
|
111
116
|
platform,
|
|
112
117
|
action,
|
|
113
118
|
namespace: LIBRARY_ACTION_NAMESPACE,
|
|
114
|
-
node,
|
|
119
|
+
node: withImmediateCloseBudget(action, node),
|
|
115
120
|
context,
|
|
116
121
|
prepared: preparedLiveAdapters?.get(action),
|
|
117
122
|
contextExtras: trustedMutationContextExtras(context),
|
|
@@ -131,6 +136,15 @@ function liveAdapterPathHint(platform, action) {
|
|
|
131
136
|
}
|
|
132
137
|
return `library/actions/${platform}/${action.replaceAll(".", "/")}.mjs`;
|
|
133
138
|
}
|
|
139
|
+
async function handleRunNetworkAction(platform, action, node, context) {
|
|
140
|
+
if (!getAdapterSurface(platform).observation?.network?.actions) return null;
|
|
141
|
+
if (action === "app.network_assert") {
|
|
142
|
+
const assertion = await import("../library/actions/shared/app/network-assert.mjs");
|
|
143
|
+
return { output: await assertion.assertNetwork({ action, node, context }) };
|
|
144
|
+
}
|
|
145
|
+
if (action !== "app.network_capture") return null;
|
|
146
|
+
return runNetworkCaptureAction(platform, node, context);
|
|
147
|
+
}
|
|
134
148
|
async function semanticResult(platform, action, node, context, forceLive = false, preparedLiveAdapters) {
|
|
135
149
|
const performanceAction = await handleRunPerformanceAction(
|
|
136
150
|
platform,
|
|
@@ -368,7 +382,9 @@ function createMetaMaskAdapters(adapter, declaredCustomActions = [], preparedLiv
|
|
|
368
382
|
return adapters;
|
|
369
383
|
}
|
|
370
384
|
export {
|
|
385
|
+
IMMEDIATE_CLOSE_ALLOWANCE_MS,
|
|
371
386
|
createMetaMaskAdapters,
|
|
372
387
|
createMetaMaskUiTransport,
|
|
373
|
-
normalizeUiWaitNode
|
|
388
|
+
normalizeUiWaitNode,
|
|
389
|
+
withImmediateCloseBudget
|
|
374
390
|
};
|
package/dist/cli.js
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import "./host.js";
|
|
2
2
|
import "./adapters/surface.js";
|
|
3
|
+
import fs from "node:fs";
|
|
3
4
|
import {
|
|
4
5
|
detectAdapter,
|
|
6
|
+
handleActions,
|
|
7
|
+
handleCall,
|
|
5
8
|
handleHarness,
|
|
6
9
|
handleLast,
|
|
7
10
|
handleLaunch,
|
|
8
11
|
handleReload,
|
|
12
|
+
handleRun,
|
|
9
13
|
handleStop,
|
|
10
14
|
parseArgs,
|
|
11
15
|
targetPath
|
|
12
16
|
} from "@farmslot/recipe-cli/harness";
|
|
13
17
|
import { stopProjectCollector } from "../library/actions/shared/analytics/collector.mjs";
|
|
18
|
+
import { loadSelectedAdapter } from "./adapters/plugin-surface.js";
|
|
14
19
|
import { adapterRegistry } from "./adapters/registry.js";
|
|
15
|
-
import {
|
|
20
|
+
import { applyDeviceTargeting } from "./commands/device-target.js";
|
|
21
|
+
import { metaMaskEngine } from "./engine.js";
|
|
22
|
+
import { walletFixturePath } from "./paths.js";
|
|
16
23
|
import { handleDoctor } from "./commands/doctor.js";
|
|
17
24
|
import { handleProvision } from "./commands/provision.js";
|
|
18
25
|
import { handleRuntimeHealth } from "./commands/runtime-health.js";
|
|
@@ -20,9 +27,7 @@ import { handleRuntimeLaunch } from "./commands/runtime-launch.js";
|
|
|
20
27
|
import { handleRuntimeDecision } from "./commands/runtime-decision.js";
|
|
21
28
|
import { handleResolveExtension } from "./commands/resolve-extension.js";
|
|
22
29
|
import { handleEnsureReady } from "./commands/ensure-ready.js";
|
|
23
|
-
import { handleRun } from "./commands/run.js";
|
|
24
30
|
import { handleSelfTest } from "./commands/self-test.js";
|
|
25
|
-
import { handleCall } from "./commands/call.js";
|
|
26
31
|
import { handleCompletionCandidates, invalidateCompletionCache } from "./commands/completion-candidates.js";
|
|
27
32
|
import { handleLogs } from "./commands/logs.js";
|
|
28
33
|
import { handleDebug } from "./commands/debug.js";
|
|
@@ -45,15 +50,35 @@ const stopOptions = {
|
|
|
45
50
|
return collector.stopped && collector.pid !== null ? [{ label: "analytics collector", pid: collector.pid }] : [];
|
|
46
51
|
}
|
|
47
52
|
};
|
|
53
|
+
const targetDevice = (command, adapter, options) => applyDeviceTargeting(command, adapter, options, { gate: true, rerun: "" });
|
|
54
|
+
const runOptions = {
|
|
55
|
+
engine: metaMaskEngine,
|
|
56
|
+
targetDevice,
|
|
57
|
+
plan: {
|
|
58
|
+
// The wallet fixture `fixtures set` seeds.
|
|
59
|
+
steps: (target) => [{
|
|
60
|
+
step: "fixture.file",
|
|
61
|
+
confidence: "static",
|
|
62
|
+
status: "ok",
|
|
63
|
+
detail: fs.existsSync(walletFixturePath(target)) ? `present: ${walletFixturePath(target)}` : `absent: ${walletFixturePath(target)} (fixtures set to seed)`
|
|
64
|
+
}],
|
|
65
|
+
launchDetail: "would launch/attach the app + heal transport (Metro/Chrome/CDP) before executing"
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const callOptions = {
|
|
69
|
+
engine: metaMaskEngine,
|
|
70
|
+
targetDevice,
|
|
71
|
+
// A wallet action makes the most useful first example.
|
|
72
|
+
exampleAction: (names) => names.find((name) => /wallet|unlock/u.test(name))
|
|
73
|
+
};
|
|
48
74
|
const COMMANDS = {
|
|
49
|
-
actions: handleActions,
|
|
75
|
+
actions: (parsed) => handleActions(parsed, { catalog: metaMaskEngine }),
|
|
50
76
|
doctor: handleDoctor,
|
|
51
77
|
"runtime-health": handleRuntimeHealth,
|
|
52
78
|
"runtime-decision": handleRuntimeDecision,
|
|
53
79
|
"runtime-launch": handleRuntimeLaunch,
|
|
54
80
|
"resolve-extension": handleResolveExtension,
|
|
55
81
|
"ensure-ready": handleEnsureReady,
|
|
56
|
-
run: handleRun,
|
|
57
82
|
"self-test": handleSelfTest
|
|
58
83
|
};
|
|
59
84
|
const OVERLAY_COMMANDS = ["install", "verify", "cleanup"];
|
|
@@ -111,10 +136,13 @@ async function main(argv) {
|
|
|
111
136
|
usage();
|
|
112
137
|
return command ? 0 : 2;
|
|
113
138
|
}
|
|
139
|
+
const refused = await loadSelectedAdapter(command, argv.slice(1));
|
|
140
|
+
if (refused !== void 0) return refused;
|
|
114
141
|
if (command === "status" || command === "health" || command === "home") {
|
|
115
142
|
return handleStatus(parseArgs(argv.slice(1)));
|
|
116
143
|
}
|
|
117
|
-
if (command === "
|
|
144
|
+
if (command === "run") return handleRun(argv.slice(1), runOptions);
|
|
145
|
+
if (command === "call") return handleCall(argv.slice(1), callOptions);
|
|
118
146
|
if (command === "completion-candidates") return handleCompletionCandidates(argv.slice(1));
|
|
119
147
|
if (command === "provision") return handleProvision(parseArgs(argv.slice(1)));
|
|
120
148
|
if (OVERLAY_COMMANDS.includes(command)) {
|
package/dist/command-contract.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { closest } from "@farmslot/recipe-cli/harness";
|
|
1
|
+
import { adapterChoices, closest } from "@farmslot/recipe-cli/harness";
|
|
2
|
+
import { configuredLibrarySources, operatorLibraryEnv } from "./adapters/plugin-surface.js";
|
|
2
3
|
const bool = () => ({ kind: "boolean" });
|
|
3
4
|
const value = (choices) => ({ kind: "value", ...choices ? { choices } : {} });
|
|
4
5
|
const optionalValue = (choices) => ({ kind: "optional-value", ...choices ? { choices } : {} });
|
|
@@ -8,9 +9,18 @@ const JSON = { "--json": bool() };
|
|
|
8
9
|
const NO_OPEN = { "--no-open": bool() };
|
|
9
10
|
const JSON_STREAM = { "--json-stream": bool() };
|
|
10
11
|
const TARGET = { "--target": value() };
|
|
11
|
-
const
|
|
12
|
+
const adapterIds = (tokens) => adapterChoices(optionValues(tokens, "--library"), {
|
|
13
|
+
configured: configuredLibrarySources(),
|
|
14
|
+
env: operatorLibraryEnv()
|
|
15
|
+
});
|
|
16
|
+
const ADAPTER = { "--adapter": { kind: "value", choices: adapterIds } };
|
|
12
17
|
const MOBILE_PLATFORM = { "--platform": value(["ios", "android"]) };
|
|
13
|
-
const ADAPTER_OR_MOBILE_PLATFORM = {
|
|
18
|
+
const ADAPTER_OR_MOBILE_PLATFORM = {
|
|
19
|
+
"--platform": {
|
|
20
|
+
kind: "value",
|
|
21
|
+
choices: (tokens) => [...adapterIds(tokens), "ios", "android"]
|
|
22
|
+
}
|
|
23
|
+
};
|
|
14
24
|
const DEVICE = { "--device": value() };
|
|
15
25
|
const RUNTIME_PORTS = {
|
|
16
26
|
"--cdp-port": value(),
|
|
@@ -152,7 +162,7 @@ const PUBLIC_COMMAND_CONTRACTS = {
|
|
|
152
162
|
prepare: {
|
|
153
163
|
usage: "mm-harness prepare [--target <checkout>] [--platform mobile|extension|core] [--mobile-platform ios|android] [--clear-metro] [--artifacts-dir <dir>] [--json]",
|
|
154
164
|
options: options(HELP, JSON, TARGET, {
|
|
155
|
-
"--platform":
|
|
165
|
+
"--platform": { kind: "value", choices: adapterIds },
|
|
156
166
|
"--mobile-platform": value(["ios", "android"]),
|
|
157
167
|
"--clear-metro": bool(),
|
|
158
168
|
"--artifacts-dir": value(),
|
|
@@ -420,6 +430,16 @@ const PUBLIC_COMMAND_CONTRACTS = {
|
|
|
420
430
|
minimumPositionals: 0
|
|
421
431
|
}
|
|
422
432
|
};
|
|
433
|
+
function optionValues(args, name) {
|
|
434
|
+
const values = [];
|
|
435
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
436
|
+
const arg = args[index];
|
|
437
|
+
if (arg === "--") break;
|
|
438
|
+
if (arg === name && args[index + 1] !== void 0) values.push(args[index += 1]);
|
|
439
|
+
else if (arg.startsWith(`${name}=`)) values.push(arg.slice(name.length + 1));
|
|
440
|
+
}
|
|
441
|
+
return values;
|
|
442
|
+
}
|
|
423
443
|
function validatePublicInvocation(argv, examples = {}) {
|
|
424
444
|
const token = argv[0];
|
|
425
445
|
if (!token || token === "--help" || token === "-h" || token === "--version" || token === "-v") return null;
|
|
@@ -487,12 +507,13 @@ function validatePublicInvocation(argv, examples = {}) {
|
|
|
487
507
|
return usageFailure("CLI_MISSING_OPTION_VALUE", name, `${optionName} requires a value.`, contract, examples);
|
|
488
508
|
}
|
|
489
509
|
if (inlineValue === void 0) index += 1;
|
|
490
|
-
|
|
491
|
-
|
|
510
|
+
const choices = typeof spec.choices === "function" ? spec.choices(tokens) : spec.choices;
|
|
511
|
+
if (choices && !choices.includes(optionValue)) {
|
|
512
|
+
const suggestion = closest(optionValue, choices);
|
|
492
513
|
return {
|
|
493
514
|
code: "CLI_INVALID_OPTION_VALUE",
|
|
494
515
|
command: name,
|
|
495
|
-
message: `${optionName} must be ${formatChoiceList(
|
|
516
|
+
message: `${optionName} must be ${formatChoiceList(choices)}; received '${optionValue}'.`,
|
|
496
517
|
userAction: actionFor(optionValue, suggestion, exampleFor(name, examples))
|
|
497
518
|
};
|
|
498
519
|
}
|
|
@@ -701,6 +722,7 @@ function exampleFor(command, examples) {
|
|
|
701
722
|
}
|
|
702
723
|
export {
|
|
703
724
|
PUBLIC_COMMAND_CONTRACTS,
|
|
725
|
+
optionValues,
|
|
704
726
|
publicCommandNames,
|
|
705
727
|
publicCommandTokens,
|
|
706
728
|
validatePublicInvocation
|
package/dist/commands/check.js
CHANGED
|
@@ -3,11 +3,12 @@ import { spawnSync } from "node:child_process";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import "../adapters/surface.js";
|
|
6
|
-
const USAGE = "mm-harness check diff [--fix] [--target <repo>] [--adapter
|
|
6
|
+
const USAGE = "mm-harness check diff [--fix] [--target <repo>] [--adapter <adapter>] [--base <ref>] [--profile fast|full] [--artifacts-dir <dir>] [--json]";
|
|
7
7
|
const JS_TS_EXT_RE = /\.(?:c|m)?jsx?$|\.tsx?$/u;
|
|
8
8
|
const FORMAT_EXT_RE = /\.(?:c|m)?jsx?$|\.tsx?$|\.json$|\.md$|\.css$|\.scss$|\.ya?ml$/u;
|
|
9
9
|
const TEST_FILE_RE = /(?:^|[./_-])(?:test|spec)\.(?:c|m)?jsx?$|(?:^|[./_-])(?:test|spec)\.tsx?$/u;
|
|
10
10
|
const ESLINT_SUPPRESSION_RE = /^\s*eslint-disable(?:-line|-next-line)?\b/u;
|
|
11
|
+
const EXTENSION_LOCALE_RE = /^app\/_locales\//u;
|
|
11
12
|
async function handleCheck(argv) {
|
|
12
13
|
const { positional, options } = parseArgs(argv);
|
|
13
14
|
const action = positional[0];
|
|
@@ -20,7 +21,7 @@ async function handleCheck(argv) {
|
|
|
20
21
|
const target = path.resolve(optionString(options, "target") ?? process.cwd());
|
|
21
22
|
const explicitAdapter = optionString(options, "adapter") ?? optionString(options, "platform");
|
|
22
23
|
const detected = explicitAdapter ?? detectAdapter(target);
|
|
23
|
-
if (detected
|
|
24
|
+
if (detected === "ios" || detected === "android") {
|
|
24
25
|
return usageOut(json, "check", `unsupported adapter '${detected}'`, USAGE);
|
|
25
26
|
}
|
|
26
27
|
const adapter = detected;
|
|
@@ -52,10 +53,12 @@ async function handleCheck(argv) {
|
|
|
52
53
|
const mergeBase = resolveMergeBase(target, baseRef);
|
|
53
54
|
const changedFiles = listChangedFiles(target, mergeBase, artifactsDir);
|
|
54
55
|
const existingChangedFiles = changedFiles.filter((file) => fs.existsSync(path.join(target, file)));
|
|
56
|
+
const untracked = untrackedFiles(target);
|
|
55
57
|
const suppressionCheck = checkNewEslintSuppressions({
|
|
56
58
|
target,
|
|
57
59
|
artifactsDir,
|
|
58
60
|
mergeBase,
|
|
61
|
+
untracked,
|
|
59
62
|
files: existingChangedFiles.filter((file) => JS_TS_EXT_RE.test(file))
|
|
60
63
|
});
|
|
61
64
|
const policyFailed = suppressionCheck.status === "fail";
|
|
@@ -97,6 +100,9 @@ async function handleCheck(argv) {
|
|
|
97
100
|
files: existingChangedFiles.filter((file) => TEST_FILE_RE.test(file))
|
|
98
101
|
})
|
|
99
102
|
);
|
|
103
|
+
if (adapter === "extension") {
|
|
104
|
+
checks.push(...runExtensionDiffChecks({ target, artifactsDir, packageJson, files: changedFiles }));
|
|
105
|
+
}
|
|
100
106
|
if (profile === "full") {
|
|
101
107
|
checks.push(runTypecheck({ target, artifactsDir, packageJson }));
|
|
102
108
|
} else {
|
|
@@ -187,10 +193,10 @@ function listChangedFiles(target, mergeBase, artifactsDir) {
|
|
|
187
193
|
}
|
|
188
194
|
};
|
|
189
195
|
if (mergeBase) {
|
|
190
|
-
addLines(runCommand("git", ["diff", "--name-only", "--diff-filter=
|
|
196
|
+
addLines(runCommand("git", ["diff", "--name-only", "--no-renames", "--diff-filter=ACMRD", `${mergeBase}...HEAD`], target).stdout);
|
|
191
197
|
}
|
|
192
|
-
addLines(runCommand("git", ["diff", "--name-only", "--diff-filter=
|
|
193
|
-
addLines(runCommand("git", ["diff", "--cached", "--name-only", "--diff-filter=
|
|
198
|
+
addLines(runCommand("git", ["diff", "--name-only", "--no-renames", "--diff-filter=ACMRD", "HEAD"], target).stdout);
|
|
199
|
+
addLines(runCommand("git", ["diff", "--cached", "--name-only", "--no-renames", "--diff-filter=ACMRD"], target).stdout);
|
|
194
200
|
addLines(runCommand("git", ["ls-files", "--others", "--exclude-standard"], target).stdout);
|
|
195
201
|
return [...files].filter((file) => !isUnderArtifactsDir(target, artifactsDir, file)).sort();
|
|
196
202
|
}
|
|
@@ -209,9 +215,7 @@ function checkNewEslintSuppressions(input) {
|
|
|
209
215
|
if (input.files.length === 0) {
|
|
210
216
|
return { id, label, status: "skip", reason: "no changed JS/TS files" };
|
|
211
217
|
}
|
|
212
|
-
const untracked =
|
|
213
|
-
runCommand("git", ["ls-files", "--others", "--exclude-standard"], input.target).stdout.split("\n").map((file) => normalizeRelativePath(file.trim())).filter(Boolean)
|
|
214
|
-
);
|
|
218
|
+
const { untracked } = input;
|
|
215
219
|
const findings = [];
|
|
216
220
|
const trackedFiles = input.files.filter((file) => !untracked.has(normalizeRelativePath(file)));
|
|
217
221
|
if (trackedFiles.length > 0) {
|
|
@@ -240,6 +244,26 @@ function checkNewEslintSuppressions(input) {
|
|
|
240
244
|
reason: `${findings.length} newly added eslint-disable directive(s)`
|
|
241
245
|
} : { id, label, status: "pass", logPath };
|
|
242
246
|
}
|
|
247
|
+
function untrackedFiles(target) {
|
|
248
|
+
return new Set(
|
|
249
|
+
runCommand("git", ["ls-files", "--others", "--exclude-standard"], target).stdout.split("\n").map((file) => normalizeRelativePath(file.trim())).filter(Boolean)
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
function runExtensionDiffChecks(input) {
|
|
253
|
+
const scripts = input.packageJson?.scripts && typeof input.packageJson.scripts === "object" ? input.packageJson.scripts : {};
|
|
254
|
+
const results = [];
|
|
255
|
+
if (typeof scripts["verify-locales"] === "string") {
|
|
256
|
+
results.push(
|
|
257
|
+
input.files.some((file) => EXTENSION_LOCALE_RE.test(normalizeRelativePath(file))) ? runCheckCommand("verify-locales", "Locale strings", input.target, input.artifactsDir, "yarn", ["verify-locales", "--quiet"]) : { id: "verify-locales", label: "Locale strings", status: "skip", reason: "no app/_locales changes" }
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
if (typeof scripts["circular-deps:check"] === "string") {
|
|
261
|
+
results.push(
|
|
262
|
+
input.files.some((file) => JS_TS_EXT_RE.test(file)) ? runCheckCommand("circular-deps", "Circular dependencies", input.target, input.artifactsDir, "yarn", ["circular-deps:check"]) : { id: "circular-deps", label: "Circular dependencies", status: "skip", reason: "no JS/TS changes" }
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
return results;
|
|
266
|
+
}
|
|
243
267
|
function findAddedSuppressions(diff) {
|
|
244
268
|
const findings = [];
|
|
245
269
|
let file = "";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EXIT, parseArgs, optionFlag, optionString, optionStrings, resolveAdapter, targetPath } from "@farmslot/recipe-cli/harness";
|
|
1
|
+
import { EXIT, listRunnableRecipes, parseArgs, optionFlag, optionString, optionStrings, resolveAdapter, resolveLibrarySources, targetPath } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import { resolveActionManifest } from "../manifest.js";
|
|
3
3
|
import {
|
|
4
4
|
invalidateCompletionCache,
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
writeCompletionCandidates
|
|
7
7
|
} from "../completions-cache.js";
|
|
8
8
|
import { importRecipeProtocol } from "../paths.js";
|
|
9
|
-
import {
|
|
9
|
+
import { metaMaskEngine } from "../engine.js";
|
|
10
10
|
async function handleCompletionCandidates(argv) {
|
|
11
11
|
const kind = argv[0];
|
|
12
12
|
const { options } = parseArgs(argv.slice(1));
|
|
@@ -20,7 +20,7 @@ async function handleCompletionCandidates(argv) {
|
|
|
20
20
|
let candidates;
|
|
21
21
|
if (kind === "actions") {
|
|
22
22
|
adapter = resolveAdapter(options).adapter;
|
|
23
|
-
const sources = await
|
|
23
|
+
const sources = await resolveLibrarySources(metaMaskEngine, optionStrings(options, "library"));
|
|
24
24
|
const { manifest } = await resolveActionManifest(adapter, optionString(options, "actionManifest"), sources);
|
|
25
25
|
const { getRecipeActionManifestActionNames } = await importRecipeProtocol();
|
|
26
26
|
candidates = getRecipeActionManifestActionNames(manifest);
|
|
@@ -30,8 +30,8 @@ async function handleCompletionCandidates(argv) {
|
|
|
30
30
|
const cacheKey = `recipes:${adapter}`;
|
|
31
31
|
candidates = readFreshCandidates(target, cacheKey);
|
|
32
32
|
if (!candidates) {
|
|
33
|
-
const sources = await
|
|
34
|
-
candidates = sources ? (await listRunnableRecipes(adapter, sources)).map((recipe) => recipe.name) : [];
|
|
33
|
+
const sources = await resolveLibrarySources(metaMaskEngine, optionStrings(options, "library")).catch(() => void 0);
|
|
34
|
+
candidates = sources ? (await listRunnableRecipes(metaMaskEngine, adapter, sources)).map((recipe) => recipe.name) : [];
|
|
35
35
|
writeCompletionCandidates(target, cacheKey, candidates);
|
|
36
36
|
}
|
|
37
37
|
}
|
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 { color, acquireCheckoutLock, detectAdapter, resolveRuntimeContextPath, ensureOverlay, newHealState, recipeRunning, adapterDetectNext, checkoutBusyOut, EXIT, usageOut, actionManifestPathOption, applyRuntimeDirOption, optionFlag, optionString, shellQuote, targetPath } from "@farmslot/recipe-cli/harness";
|
|
5
|
+
import { adapterPluginChecks, color, acquireCheckoutLock, detectAdapter, 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";
|
|
@@ -158,7 +158,10 @@ async function handleDoctor({ options }) {
|
|
|
158
158
|
const checks = [
|
|
159
159
|
...result.checks,
|
|
160
160
|
runtimeCheck,
|
|
161
|
-
...await readiness.liveChecks?.(target) ?? []
|
|
161
|
+
...await readiness.liveChecks?.(target) ?? [],
|
|
162
|
+
...await platformDoctorChecks(adapter, target),
|
|
163
|
+
// Which library plugin code this process loaded: library, module and digest.
|
|
164
|
+
...adapterPluginChecks()
|
|
162
165
|
];
|
|
163
166
|
const requiredChecks = requiredDoctorCheckSummary(checks);
|
|
164
167
|
const doctorResult = {
|
|
@@ -244,6 +247,20 @@ async function handleDoctor({ options }) {
|
|
|
244
247
|
}
|
|
245
248
|
return doctorResult.status === "pass" ? 0 : 1;
|
|
246
249
|
}
|
|
250
|
+
async function platformDoctorChecks(adapter, target) {
|
|
251
|
+
try {
|
|
252
|
+
return await getAdapterSurface(adapter).doctor?.(target) ?? [];
|
|
253
|
+
} catch (error) {
|
|
254
|
+
return [{
|
|
255
|
+
id: `adapter-plugin:${adapter}:doctor`,
|
|
256
|
+
status: "fail",
|
|
257
|
+
required: true,
|
|
258
|
+
message: `${adapter}'s doctor checks failed to run.`,
|
|
259
|
+
detail: error instanceof Error ? error.message : String(error),
|
|
260
|
+
userAction: `fix the doctor() of the ${adapter} adapter, then rerun mm-harness doctor --adapter ${adapter}`
|
|
261
|
+
}];
|
|
262
|
+
}
|
|
263
|
+
}
|
|
247
264
|
function doctorRuntimeCheck(runtime, error, expectLive) {
|
|
248
265
|
if (error) {
|
|
249
266
|
return {
|
package/dist/commands/help.js
CHANGED
|
@@ -5,7 +5,7 @@ import { handleHelpReview } from "./review.js";
|
|
|
5
5
|
import "../adapters/surface.js";
|
|
6
6
|
const UNSCOPED_NEXT = "cd into a MetaMask checkout or pass --adapter <mobile|extension|core|terminal>";
|
|
7
7
|
function validHelpLine(value) {
|
|
8
|
-
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", "
|
|
8
|
+
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
9
|
}
|
|
10
10
|
function scopedSections(topic, adapter) {
|
|
11
11
|
const select = (lines) => lines.flatMap((line) => typeof line === "string" ? [line] : line.adapters.includes(adapter) ? [line.text] : []);
|
|
@@ -9,15 +9,15 @@ import {
|
|
|
9
9
|
parseRemoteFlagSpec,
|
|
10
10
|
remoteFlagRequestFor
|
|
11
11
|
} from "../../feature-flags.js";
|
|
12
|
-
import {
|
|
12
|
+
import { webDappOnlyLaunchFlags } from "../../adapters/web-dapp/launch.js";
|
|
13
13
|
import { shellQuote } from "./quote.js";
|
|
14
14
|
async function runDeviceLaunch(context, profile) {
|
|
15
15
|
const { adapter, options, target, heal, jsonOutput, machine, stream, usage } = context;
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
16
|
+
const webDappOnly = webDappOnlyLaunchFlags(options);
|
|
17
|
+
if (webDappOnly.length > 0) {
|
|
18
18
|
return usage(
|
|
19
|
-
`${
|
|
20
|
-
"drop
|
|
19
|
+
`${webDappOnly.join(", ")} apply only to adapters that extend web-dapp (e.g. --adapter terminal); ${adapter} does not read them.`,
|
|
20
|
+
"drop those flags, or pass --adapter terminal"
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
23
|
const wantBuild = flag(options, "build");
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { optionFlag, optionString, requiredOption } from "@farmslot/recipe-cli/harness";
|
|
1
|
+
import { activateRecipeRuntimeEnvironment, optionFlag, optionString, requiredOption, runRecipe } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import { mkdtemp } from "node:fs/promises";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { loadActionManifest, validateManifest } from "../manifest.js";
|
|
6
6
|
import { recipePath, runnerDir } from "../paths.js";
|
|
7
|
-
import {
|
|
7
|
+
import { metaMaskEngine } from "../engine.js";
|
|
8
8
|
async function handleSelfTest({ options }) {
|
|
9
9
|
const result = await runSelfTest(options);
|
|
10
10
|
if (optionFlag(options, "json")) console.log(JSON.stringify(result, null, 2));
|
|
@@ -23,9 +23,14 @@ async function runSelfTest(options) {
|
|
|
23
23
|
const manifestValidation = await validateManifest(manifest);
|
|
24
24
|
const smokeRecipe = recipePath(`${adapter}/runner/smoke.recipe.json`);
|
|
25
25
|
const artifactsDir = path.join(root, adapter);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
const runtimeOptions = { platform: { skipExtensionRuntimePrepare: true } };
|
|
27
|
+
const restoreRuntimeEnvironment = activateRecipeRuntimeEnvironment(adapter, runnerDir, runtimeOptions);
|
|
28
|
+
let result;
|
|
29
|
+
try {
|
|
30
|
+
result = await runRecipe(metaMaskEngine, adapter, smokeRecipe, artifactsDir, runnerDir, void 0, runtimeOptions);
|
|
31
|
+
} finally {
|
|
32
|
+
restoreRuntimeEnvironment();
|
|
33
|
+
}
|
|
29
34
|
runs.push({ adapter, manifestValidation: manifestValidation.summary, artifactsDir, result });
|
|
30
35
|
}
|
|
31
36
|
} finally {
|