@deeeed/metamask-harness 0.78.0 → 0.80.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 +55 -0
- package/README.md +1 -1
- package/adapters/extension/ensure-browser.sh +2 -2
- package/adapters/extension/inject.mjs +0 -1
- package/adapters/extension/launch-browser.cjs +39 -613
- package/adapters/extension/readiness.mjs +2 -5
- package/adapters/extension/reattach.sh +2 -2
- package/adapters/extension/stamp-runtime-title.cjs +1 -1
- package/adapters/manifest.json +2 -34
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +57 -1358
- package/adapters/mobile/bridge-runtime/teaching.cjs +20 -0
- package/adapters/mobile/inject.sh +16 -0
- package/adapters/mobile/launch-console-forwarder.cjs +1 -2
- package/adapters/mobile/open-device.sh +2 -2
- package/adapters/mobile/reload-app.mjs +4 -4
- package/adapters/mobile/reset-app-data.sh +1 -1
- package/adapters/mobile/start-console-forwarder.sh +3 -2
- package/adapters/mobile/start-metro.sh +17 -12
- package/adapters/mobile/wait-for-bridge.cjs +2 -2
- package/adapters/shared/ensure-runner-deps.sh +2 -2
- package/adapters/shared/harness-source-fingerprint.mjs +13 -8
- package/adapters/shared/open-debug.mjs +2 -2
- package/adapters/shared/runner-deps-ready.mjs +1 -1
- package/adapters/shared/sync-wallet-fixture.sh +8 -5
- package/adapters/terminal/cleanup.mjs +2 -1
- package/adapters/terminal/inject.mjs +2 -1
- package/adapters/terminal/lib/cdp-client.mjs +1 -1
- package/bin/mm-harness +9 -28
- package/dist/adapters/checkout-files.js +16 -0
- package/dist/adapters/console-capture.js +14 -1
- package/dist/adapters/core/actions.js +4 -3
- package/dist/adapters/core/overlay.js +1 -1
- package/dist/adapters/core/readiness.js +28 -1
- package/dist/adapters/core/run.js +3 -3
- package/dist/adapters/core/surface.js +22 -5
- package/dist/adapters/extension/browser-pid.js +56 -0
- package/dist/adapters/extension/console-capture.js +1 -1
- package/dist/adapters/extension/doctor-checks.js +1 -1
- package/dist/adapters/extension/ensure-ready.js +5 -4
- package/dist/adapters/extension/extension-id.js +1 -1
- package/dist/adapters/extension/feature-flags.js +1 -1
- package/dist/adapters/extension/fixtures.js +1 -2
- package/dist/adapters/extension/launch.js +4 -5
- package/dist/adapters/extension/launched-browser.js +1 -2
- package/dist/adapters/extension/network-observer.js +1 -1
- package/dist/adapters/extension/overlay.js +1 -1
- package/dist/adapters/extension/product-config.js +1 -1
- package/dist/adapters/extension/readiness.js +1 -1
- package/dist/adapters/extension/reload.js +1 -1
- package/dist/adapters/extension/run.js +24 -10
- package/dist/adapters/extension/runtime-decision.js +3 -2
- package/dist/adapters/extension/runtime.js +9 -5
- package/dist/adapters/extension/surface.js +20 -5
- package/dist/adapters/extension/verify.js +2 -2
- package/dist/adapters/harness-freshness.js +2 -1
- package/dist/adapters/mobile/android-gfxinfo-performance.js +1 -3
- package/dist/adapters/mobile/app-identity.js +10 -0
- package/dist/adapters/mobile/doctor-checks.js +1 -1
- package/dist/adapters/mobile/fixtures.js +1 -1
- package/dist/adapters/mobile/launch.js +27 -28
- package/dist/adapters/mobile/lifecycle.js +1 -1
- package/dist/adapters/mobile/metro-env.js +9 -59
- package/dist/adapters/mobile/performance-observer.js +1 -1
- package/dist/adapters/mobile/prepare-target.js +1 -1
- package/dist/adapters/mobile/prepare.js +4 -5
- package/dist/adapters/mobile/provision.js +1 -1
- package/dist/adapters/mobile/readiness.js +1 -1
- package/dist/adapters/mobile/recording-target.js +15 -0
- package/dist/adapters/mobile/release-artifact-state.js +1 -1
- package/dist/adapters/mobile/reload.js +1 -1
- package/dist/adapters/mobile/run.js +9 -8
- package/dist/adapters/mobile/runtime-decision.js +5 -7
- package/dist/adapters/mobile/source-freshness.js +22 -126
- package/dist/adapters/mobile/surface.js +31 -6
- package/dist/adapters/mobile/ui.js +16 -5
- package/dist/adapters/mobile/verify.js +2 -3
- package/dist/adapters/performance/cdp-trace.js +1 -1
- package/dist/adapters/performance/device-platform.js +1 -1
- package/dist/adapters/registry.js +2 -14
- package/dist/adapters/slot-ports.js +1 -1
- package/dist/adapters/surface.js +1 -0
- package/dist/adapters/terminal/console-capture.js +1 -1
- package/dist/adapters/terminal/launch.js +1 -1
- package/dist/adapters/terminal/run.js +25 -2
- package/dist/adapters/terminal/surface.js +12 -4
- package/dist/adapters.js +8 -4
- package/dist/advisor-policy.js +1 -1
- package/dist/checkout-view.js +1 -2
- package/dist/cli.js +28 -15
- package/dist/command-contract.js +1 -26
- package/dist/commands/call.js +10 -24
- package/dist/commands/check.js +3 -4
- package/dist/commands/checklist.js +1 -1
- package/dist/commands/completion-candidates.js +2 -10
- package/dist/commands/config.js +2 -2
- package/dist/commands/core-readiness.js +12 -7
- package/dist/commands/debug.js +3 -3
- package/dist/commands/device-target.js +5 -5
- package/dist/commands/doctor.js +2 -14
- package/dist/commands/domain.js +2 -2
- package/dist/commands/ensure-ready.js +1 -7
- package/dist/commands/fixtures.js +5 -6
- package/dist/commands/help.js +3 -4
- package/dist/commands/launch/device.js +10 -17
- package/dist/commands/launch/extension.js +3 -9
- package/dist/commands/launch/mobile.js +1 -1
- package/dist/commands/list-executables.js +1 -3
- package/dist/commands/logs.js +3 -3
- package/dist/commands/manifest.js +1 -12
- package/dist/commands/mobile-device-view.js +4 -2
- package/dist/commands/overlay.js +110 -0
- package/dist/commands/pin.js +1 -1
- package/dist/commands/pr-body.js +2 -2
- package/dist/commands/prepare.js +6 -11
- package/dist/commands/provision.js +3 -12
- package/dist/commands/recipe-advice.js +1 -2
- package/dist/commands/recipe-quality.js +2 -3
- package/dist/commands/resolve-extension.js +1 -7
- package/dist/commands/review.js +4 -4
- package/dist/commands/run-engine.js +12 -51
- package/dist/commands/run.js +4 -25
- package/dist/commands/runtime-decision.js +1 -6
- package/dist/commands/runtime-health.js +1 -7
- package/dist/commands/runtime-launch.js +1 -13
- package/dist/commands/self-test.js +2 -6
- package/dist/commands/status-watch.js +1 -2
- package/dist/commands/status.js +2 -5
- package/dist/commands/task-init.js +2 -3
- package/dist/commands/tutorial.js +2 -2
- package/dist/commands/update.js +1 -1
- package/dist/completions-cache.js +1 -1
- package/dist/console-classifier.js +19 -0
- package/dist/discovery.js +1 -1
- package/dist/doctor.js +3 -4
- package/dist/funding-execution-context.js +15 -1
- package/dist/host.js +32 -0
- package/dist/index.js +1 -6
- package/dist/live-tsx.js +49 -0
- package/dist/mm-harness-cli.js +2 -4
- package/dist/network-observation.js +4 -4
- package/dist/paths.js +48 -78
- package/dist/performance-observation.js +2 -2
- package/dist/progress.js +1 -1
- package/dist/recipe-assistance-context.js +2 -4
- package/dist/recipe-security.js +2 -59
- package/dist/review/knowledge.js +3 -3
- package/dist/runner.js +5 -3
- package/dist/runtime-context.js +1 -1
- package/dist/task-view.js +3 -4
- package/docs/CONTRIBUTING.md +3 -3
- package/docs/cli-contract.md +2 -2
- package/docs/feature-guard.md +90 -0
- package/library/README.md +3 -1
- package/library/actions/core/perps/_controller.mjs +153 -130
- package/library/actions/core/perps/quote_fees.mjs +58 -0
- package/library/actions/core/wallet/_fixture-accounts.mjs +69 -0
- package/library/actions/core/wallet/list_accounts.mjs +14 -57
- package/library/actions/extension/feature_flags/state.mjs +1 -1
- package/library/actions/extension/platform/cdp.mjs +2 -8
- package/library/actions/harness-exports.mjs +1 -6
- package/library/actions/mobile/app/network-control.mjs +6 -8
- package/library/actions/mobile/perps/prepare_local_snapshot_endpoint.mjs +1 -1
- package/library/actions/mobile/platform/bridge.mjs +8 -8
- package/library/actions/mobile/platform/native-session-name.mjs +21 -1
- package/library/actions/mobile/platform/native-session.mjs +3 -4
- package/library/actions/mobile/platform/observe-ui.mjs +12 -6
- package/library/actions/mobile/ui/native-navigation.mjs +4 -3
- package/library/actions/mobile/wallet/native-ui.mjs +3 -2
- package/library/actions/shared/analytics/_adapter.mjs +1 -1
- package/library/actions/shared/console-findings.mjs +1 -1
- package/library/actions/terminal/platform/runtime.mjs +2 -1
- package/library/manifests/core.action-manifest.json +83 -13
- package/package.json +8 -8
- package/adapters/extension/lib/slot-title.cjs +0 -292
- package/adapters/mobile/bridge-runtime/console-forwarder.cjs +0 -472
- package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +0 -125
- package/adapters/mobile/bridge-runtime/lib/cdp-broker.cjs +0 -1055
- package/adapters/mobile/bridge-runtime/lib/cdp-eval.cjs +0 -110
- package/adapters/mobile/bridge-runtime/lib/config.cjs +0 -61
- package/adapters/mobile/bridge-runtime/lib/console-format.cjs +0 -53
- package/adapters/mobile/bridge-runtime/lib/devtools-proxy.cjs +0 -177
- package/adapters/mobile/bridge-runtime/lib/issue-capture.cjs +0 -446
- package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +0 -84
- package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +0 -403
- package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +0 -116
- package/adapters/mobile/coalesce-metro-log.cjs +0 -24
- package/adapters/mobile/launch-metro.cjs +0 -77
- package/adapters/mobile/metro-config.cjs +0 -98
- package/adapters/mobile/metro-log-generation.cjs +0 -106
- package/dist/adapters/mobile/frame-metrics.js +0 -118
- package/dist/adapters/mobile/video-recorder.js +0 -289
- package/dist/artifact-files.js +0 -92
- package/dist/checkout-lock.js +0 -149
- package/dist/cli-color.js +0 -98
- package/dist/command-journal.js +0 -308
- package/dist/commands/last.js +0 -60
- package/dist/commands/launch/index.js +0 -109
- package/dist/commands/parse-args.js +0 -279
- package/dist/commands/reload.js +0 -41
- package/dist/commands/run-report.js +0 -241
- package/dist/commands/shared.js +0 -323
- package/dist/commands/stop.js +0 -60
- package/dist/devices.js +0 -100
- package/dist/execution-provenance.js +0 -332
- package/dist/harness.js +0 -451
- package/dist/heal-bounds.js +0 -137
- package/dist/json-stream.js +0 -60
- package/dist/leaf-invoke.js +0 -19
- package/dist/library-provenance.js +0 -33
- package/dist/live-adapter-contract.js +0 -380
- package/dist/recording-target.js +0 -120
- package/dist/run-diagnostics.js +0 -364
- package/dist/run-recording.js +0 -481
- package/dist/runtime-proof.js +0 -90
- package/library/actions/mobile/platform/tool-paths.mjs +0 -123
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
function resolveExtensionBrowserPid(projectRoot, artifactsDir, cdpPort) {
|
|
5
|
+
const explicit = parsePositivePid(process.env.METAMASK_RECIPE_EXTENSION_BROWSER_PID);
|
|
6
|
+
if (explicit) return explicit;
|
|
7
|
+
if (cdpPort) {
|
|
8
|
+
const lsof = spawnSync("lsof", ["-nP", `-iTCP:${cdpPort}`, "-sTCP:LISTEN", "-t"], {
|
|
9
|
+
cwd: projectRoot,
|
|
10
|
+
encoding: "utf8"
|
|
11
|
+
});
|
|
12
|
+
if (lsof.status === 0) {
|
|
13
|
+
const pid = parsePositivePid(String(lsof.stdout).split(/\s+/u).find(Boolean));
|
|
14
|
+
if (pid) return pid;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
for (const file of [
|
|
18
|
+
path.join(artifactsDir, "extension-runtime/runtime.json"),
|
|
19
|
+
path.join(projectRoot, "temp/recipe/runtime/runtime.json")
|
|
20
|
+
]) {
|
|
21
|
+
const pid = parsePositivePid(readJsonFile(file)?.pid);
|
|
22
|
+
if (pid) return pid;
|
|
23
|
+
}
|
|
24
|
+
for (const file of [
|
|
25
|
+
path.join(projectRoot, "temp/recipe/runtime/chromium.pid"),
|
|
26
|
+
path.join(projectRoot, "temp/recipe/runtime/browser.pid")
|
|
27
|
+
]) {
|
|
28
|
+
const pid = parsePositivePid(readTextFile(file));
|
|
29
|
+
if (pid) return pid;
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
function parsePositivePid(value) {
|
|
34
|
+
const pid = Number(String(value ?? "").trim());
|
|
35
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
36
|
+
}
|
|
37
|
+
function readJsonFile(file) {
|
|
38
|
+
if (!fs.existsSync(file)) return null;
|
|
39
|
+
try {
|
|
40
|
+
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
41
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function readTextFile(file) {
|
|
47
|
+
if (!fs.existsSync(file)) return "";
|
|
48
|
+
try {
|
|
49
|
+
return fs.readFileSync(file, "utf8");
|
|
50
|
+
} catch {
|
|
51
|
+
return "";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
resolveExtensionBrowserPid
|
|
56
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import { recipeRuntimePath } from "@farmslot/recipe-cli/harness";
|
|
2
3
|
import { verifyCapture } from "../../../library/actions/shared/console-collector.mjs";
|
|
3
|
-
import { recipeRuntimePath } from "../../paths.js";
|
|
4
4
|
import { ensureConsoleCollector } from "../console-capture.js";
|
|
5
5
|
function extensionCaptureFiles(target) {
|
|
6
6
|
return {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { spawnSync } from "node:child_process";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
import fs from "node:fs";
|
|
4
5
|
import { createRequire } from "node:module";
|
|
5
6
|
import path from "node:path";
|
|
6
|
-
import { recipeRuntimeDir } from "../../paths.js";
|
|
7
7
|
function extensionBrowserDoctorCheck(target) {
|
|
8
8
|
const requireFromTarget = createRequire(path.join(path.resolve(target), "package.json"));
|
|
9
9
|
for (const packageName of ["@playwright/test", "playwright"]) {
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { createRequire } from "node:module";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import { recipeRuntimeDir, runnerDir } from "../../paths.js";
|
|
4
4
|
import { resolveExtensionId } from "./extension-id.js";
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
path.join(runnerDir, "adapters/extension/lib/slot-title.cjs")
|
|
5
|
+
const { stampHomeTabsViaCdp } = createRequire(import.meta.url)(
|
|
6
|
+
"@farmslot/adapter-web/slot-title"
|
|
8
7
|
);
|
|
9
8
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
9
|
async function jsonList(port) {
|
|
@@ -200,6 +199,8 @@ async function ensureExtensionReady(target, options) {
|
|
|
200
199
|
target: resolved,
|
|
201
200
|
cdpPort,
|
|
202
201
|
extensionId,
|
|
202
|
+
homePage: "home.html",
|
|
203
|
+
defaultTitle: "MetaMask",
|
|
203
204
|
runtimeDir: recipeRuntimeDir()
|
|
204
205
|
});
|
|
205
206
|
if (stamp.slotId || stamp.stamped > 0 || stamp.skipped > 0) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { recipeRuntimeDir } from "
|
|
4
|
+
import { recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
|
|
5
5
|
import { releaseArtifactState, runtimeDistCheck } from "./runtime-decision.js";
|
|
6
6
|
const DIST_MANIFEST = "dist/chrome/manifest.json";
|
|
7
7
|
function extensionIdFromKey(keyBase64) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
|
|
3
4
|
import { normalizeFeatureFlagRecord } from "../../feature-flags.js";
|
|
4
|
-
import { recipeRuntimeDir } from "../../paths.js";
|
|
5
5
|
import { releaseArtifactState } from "./runtime-decision.js";
|
|
6
6
|
function extensionRuntimeManifestPath(target) {
|
|
7
7
|
return path.join(
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { colorHumanMessage } from "
|
|
3
|
+
import { colorHumanMessage, EXIT, spawnScriptStreaming } from "@farmslot/recipe-cli/harness";
|
|
4
4
|
import { FIXTURE_STREAM_TIMEOUT_MS } from "../../commands/fixtures.js";
|
|
5
|
-
import { EXIT, spawnScriptStreaming } from "../../commands/shared.js";
|
|
6
5
|
import { sameFeatureFlags } from "../../feature-flags.js";
|
|
7
6
|
import { runnerDir } from "../../paths.js";
|
|
8
7
|
import { readExtensionPinnedFlags } from "./feature-flags.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { colorHumanMessage } from "
|
|
2
|
+
import { colorHumanMessage, EXIT, spawnScript } from "@farmslot/recipe-cli/harness";
|
|
3
3
|
import {
|
|
4
4
|
extensionDepsBlock,
|
|
5
5
|
extensionRuntimeReusable,
|
|
@@ -7,18 +7,17 @@ import {
|
|
|
7
7
|
launchExtension
|
|
8
8
|
} from "../../commands/launch/extension.js";
|
|
9
9
|
import { shellQuote } from "../../commands/launch/quote.js";
|
|
10
|
-
import { EXIT, spawnScript } from "../../commands/shared.js";
|
|
11
10
|
import {
|
|
12
11
|
fixtureFeatureFlags,
|
|
13
12
|
sameFeatureFlags,
|
|
14
13
|
toRemoteFlagSpec
|
|
15
14
|
} from "../../feature-flags.js";
|
|
16
|
-
import { RECOVERY_CODE } from "../../heal-bounds.js";
|
|
17
15
|
import { runnerDir, walletFixturePath } from "../../paths.js";
|
|
18
16
|
import { ensureExtensionConsoleCapture } from "./console-capture.js";
|
|
19
17
|
import { readExtensionPinnedFlags } from "./feature-flags.js";
|
|
20
18
|
import { extensionProductConfigBlock } from "./product-config.js";
|
|
21
19
|
import { releaseArtifactState, runtimeDistCheck } from "./runtime-decision.js";
|
|
20
|
+
const CHROME_REOPENED = "chrome.reopened";
|
|
22
21
|
const DEFAULT_EXTENSION_DAPP_URL = "https://metamask.github.io/test-dapp/";
|
|
23
22
|
function verifyExtensionPin(target, requested) {
|
|
24
23
|
const pinned = readExtensionPinnedFlags(target);
|
|
@@ -223,7 +222,7 @@ const extensionLaunchProfile = {
|
|
|
223
222
|
originalError: rebuildAttempt.output.trim() || void 0
|
|
224
223
|
});
|
|
225
224
|
},
|
|
226
|
-
recovery: () => ({ code:
|
|
225
|
+
recovery: () => ({ code: CHROME_REOPENED, restartApp: false }),
|
|
227
226
|
// --watch only restarts the webpack watcher; the snapshot, and its pin, are
|
|
228
227
|
// untouched, so the live record is reported rather than verified against a
|
|
229
228
|
// request the watcher could never apply (--remote-flag is refused with it;
|
|
@@ -307,7 +306,7 @@ const extensionLaunchProfile = {
|
|
|
307
306
|
return void 0;
|
|
308
307
|
},
|
|
309
308
|
verifyArgs: () => process.env.CDP_PORT ? ["--cdp-port", process.env.CDP_PORT] : [],
|
|
310
|
-
platformLabel: ({
|
|
309
|
+
platformLabel: ({ platformTarget, displayMode }) => platformTarget ?? displayMode,
|
|
311
310
|
deviceLabel: ({ displayMode }) => displayMode
|
|
312
311
|
};
|
|
313
312
|
export {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import { recipeRuntimeDir, isRecord } from "@farmslot/recipe-cli/harness";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import path from "node:path";
|
|
4
|
-
import { isRecord } from "../../commands/parse-args.js";
|
|
5
|
-
import { recipeRuntimeDir } from "../../paths.js";
|
|
6
5
|
function readRecord(file) {
|
|
7
6
|
try {
|
|
8
7
|
const recorded = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { readRuntimeContextField, resolveRuntimeContextPath } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import fs from "node:fs";
|
|
2
|
-
import { readRuntimeContextField, resolveRuntimeContextPath } from "../../harness.js";
|
|
3
3
|
import { resolveExtensionSlotPorts } from "../slot-ports.js";
|
|
4
4
|
function hasArg(args, needle) {
|
|
5
5
|
return args.some((arg) => arg === needle || arg.startsWith(`${needle}=`));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { shellQuote } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import productConfig from "../../../adapters/extension/lib/product-config.cjs";
|
|
5
|
-
import { shellQuote } from "../../commands/parse-args.js";
|
|
6
6
|
const EXTENSION_PRODUCT_CONFIG_FINGERPRINT_FILENAME = "extension-product-config.sha256";
|
|
7
7
|
function extensionProductConfigFingerprint(target, environment = process.env) {
|
|
8
8
|
const resolution = productConfig.resolveExtensionInfuraProjectId(target, environment);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { optionFlag, optionString, parsePort } from "
|
|
1
|
+
import { optionFlag, optionString, parsePort } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import { ensureExtensionPerpsBuildFlag, extensionBrowserDoctorCheck, extensionBrowserResolutionDoctorCheck } from "./doctor-checks.js";
|
|
3
3
|
import { readExtensionPinnedFlags } from "./feature-flags.js";
|
|
4
4
|
import { extensionProductConfigBlock } from "./product-config.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { EXIT, spawnScript, usageOut } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import path from "node:path";
|
|
2
|
-
import { EXIT, spawnScript, usageOut } from "../../commands/shared.js";
|
|
3
3
|
import { runnerDir } from "../../paths.js";
|
|
4
4
|
function reloadExtension(target, json) {
|
|
5
5
|
const adapter = "extension";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { optionString } from "
|
|
2
|
-
import {
|
|
1
|
+
import { optionFlag, optionString } from "@farmslot/recipe-cli/harness";
|
|
2
|
+
import { verifyOwnedCollectorControl } from "../console-capture.js";
|
|
3
|
+
import { resolveExtensionBrowserPid } from "./browser-pid.js";
|
|
3
4
|
import {
|
|
4
5
|
ensureExtensionConsoleCapture,
|
|
5
6
|
extensionCaptureFiles,
|
|
@@ -7,9 +8,15 @@ import {
|
|
|
7
8
|
verifyExtensionConsoleControl
|
|
8
9
|
} from "./console-capture.js";
|
|
9
10
|
import { launchedBrowser } from "./launched-browser.js";
|
|
11
|
+
const AUTOLAUNCH_ENV = "METAMASK_RECIPE_EXTENSION_AUTOLAUNCH";
|
|
10
12
|
const extensionRun = {
|
|
13
|
+
platformOptions: (options) => ({ launchExistingDist: optionFlag(options, "launchExistingDist") }),
|
|
14
|
+
activateEnv(_projectRoot, options) {
|
|
15
|
+
if (options.platform?.launchExistingDist) process.env[AUTOLAUNCH_ENV] = "1";
|
|
16
|
+
},
|
|
17
|
+
envKeys: [AUTOLAUNCH_ENV],
|
|
11
18
|
async prepareRuntime(projectRoot, runtimeOptions) {
|
|
12
|
-
if (runtimeOptions.skipExtensionRuntimePrepare === true) return;
|
|
19
|
+
if (runtimeOptions.platform?.skipExtensionRuntimePrepare === true) return;
|
|
13
20
|
const { releaseArtifactState, runtimeDistCheck } = await import("./runtime-decision.js");
|
|
14
21
|
const artifact = releaseArtifactState(projectRoot);
|
|
15
22
|
const runtimeSnapshot = runtimeDistCheck(projectRoot, artifact);
|
|
@@ -24,7 +31,7 @@ const extensionRun = {
|
|
|
24
31
|
projectRoot,
|
|
25
32
|
cdpPort: runtimeOptions.cdpPort,
|
|
26
33
|
slot: runtimeOptions.slot,
|
|
27
|
-
launchExistingDist: runtimeOptions.launchExistingDist === true,
|
|
34
|
+
launchExistingDist: runtimeOptions.platform?.launchExistingDist === true,
|
|
28
35
|
validationRuntimeDir: runtimeOptions.validationRuntimeDir,
|
|
29
36
|
pageMode: "home-or-sidepanel"
|
|
30
37
|
});
|
|
@@ -33,12 +40,11 @@ const extensionRun = {
|
|
|
33
40
|
// the slot's for the check, and the slot's come back afterwards.
|
|
34
41
|
runtimeCheck({ target, options, heal, state, json, onRecovery }) {
|
|
35
42
|
return async () => {
|
|
36
|
-
const cliOptions = options;
|
|
37
43
|
const previousCdpPort = process.env.CDP_PORT;
|
|
38
44
|
const previousRecipeCdpPort = process.env.RECIPE_CDP_PORT;
|
|
39
45
|
const previousWatcherPort = process.env.WATCHER_PORT;
|
|
40
|
-
const explicitCdpPort = optionString(
|
|
41
|
-
const explicitWatcherPort = optionString(
|
|
46
|
+
const explicitCdpPort = optionString(options, "cdpPort");
|
|
47
|
+
const explicitWatcherPort = optionString(options, "watcherPort") ?? optionString(options, "metroPort");
|
|
42
48
|
if (explicitCdpPort) {
|
|
43
49
|
process.env.CDP_PORT = explicitCdpPort;
|
|
44
50
|
process.env.RECIPE_CDP_PORT = explicitCdpPort;
|
|
@@ -54,12 +60,20 @@ const extensionRun = {
|
|
|
54
60
|
}
|
|
55
61
|
};
|
|
56
62
|
},
|
|
57
|
-
launchedBrowser: (target, artifactsDir, cdpPort) => launchedBrowser(target, artifactsDir, cdpPort)
|
|
63
|
+
launchedBrowser: (target, artifactsDir, cdpPort) => launchedBrowser(target, artifactsDir, cdpPort),
|
|
64
|
+
browserProvenance: (browser) => ({
|
|
65
|
+
browser: browser.browser,
|
|
66
|
+
browser_version: browser.version,
|
|
67
|
+
browser_source: browser.source,
|
|
68
|
+
extension_loading: browser.extensionLoading
|
|
69
|
+
})
|
|
58
70
|
};
|
|
59
71
|
const extensionRecording = {
|
|
60
72
|
target: (context) => resolveExtensionRecordingTarget(context),
|
|
61
73
|
framed: {
|
|
62
|
-
browserPid: (projectRoot, artifactsDir, cdpPort) => resolveExtensionBrowserPid(projectRoot, artifactsDir, cdpPort)
|
|
74
|
+
browserPid: (projectRoot, artifactsDir, cdpPort) => resolveExtensionBrowserPid(projectRoot, artifactsDir, cdpPort),
|
|
75
|
+
// cdp.mjs snapshots the framed recording of this pid.
|
|
76
|
+
activePidEnv: "METAMASK_RECIPE_EXTENSION_ACTIVE_RECORDING_PID"
|
|
63
77
|
}
|
|
64
78
|
};
|
|
65
79
|
async function resolveExtensionRecordingTarget(context) {
|
|
@@ -80,7 +94,7 @@ const extensionDiagnostics = {
|
|
|
80
94
|
start: (projectRoot) => ensureExtensionConsoleCapture(projectRoot),
|
|
81
95
|
files: (projectRoot) => extensionCaptureFiles(projectRoot),
|
|
82
96
|
cdpPort: () => extensionCdpPort(),
|
|
83
|
-
verifyControl: (capture) => verifyExtensionConsoleControl(capture)
|
|
97
|
+
verifyControl: (capture) => verifyOwnedCollectorControl(capture, () => verifyExtensionConsoleControl(capture))
|
|
84
98
|
}
|
|
85
99
|
};
|
|
86
100
|
const extensionObservation = {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { recipeHarnessPath, recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { execFileSync } from "node:child_process";
|
|
2
3
|
import crypto from "node:crypto";
|
|
3
4
|
import fs from "node:fs";
|
|
@@ -6,8 +7,8 @@ import { extensionTreeSha256 } from "./artifact-integrity.js";
|
|
|
6
7
|
import {
|
|
7
8
|
depsCheck,
|
|
8
9
|
INSTALL_MARKERS
|
|
9
|
-
} from "@farmslot/recipe-
|
|
10
|
-
import {
|
|
10
|
+
} from "@farmslot/recipe-runner/runtime/deps-readiness";
|
|
11
|
+
import { recipeWatchLogCandidates } from "../../paths.js";
|
|
11
12
|
const WEBPACK_DIRECT_INPUTS = ["package.json", "yarn.lock", ".yarnrc.yml", ".tool-versions"];
|
|
12
13
|
const WEBPACK_RECURSIVE_INPUTS = ["development/webpack"];
|
|
13
14
|
const WEBPACK_CACHE_DIR = "node_modules/.cache/webpack";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { recipeHarnessPath, recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { spawn } from "node:child_process";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
5
|
import path from "node:path";
|
|
5
|
-
import { importRecipeHarnessRuntimeBrowserExtension, importRecipeHarnessRuntimeCdp,
|
|
6
|
+
import { importRecipeHarnessRuntimeBrowserExtension, importRecipeHarnessRuntimeCdp, resolveFarmslotPoolDir, runnerDir } from "../../paths.js";
|
|
6
7
|
import { poolFilesForHost } from "../resolve-slot-ports.js";
|
|
7
8
|
import { profileProcessPids } from "./validation-process-ownership.js";
|
|
8
9
|
const require2 = createRequire(import.meta.url);
|
|
@@ -537,12 +538,15 @@ function resolveCdpPort(rawPort, slot) {
|
|
|
537
538
|
return port;
|
|
538
539
|
}
|
|
539
540
|
function resolveExtensionSlot(projectRoot, requestedSlot) {
|
|
540
|
-
const
|
|
541
|
-
if (!
|
|
542
|
-
if (requestedSlot)
|
|
541
|
+
const poolsDir = resolveFarmslotPoolDir();
|
|
542
|
+
if (!poolsDir) {
|
|
543
|
+
if (requestedSlot) {
|
|
544
|
+
throw new Error(
|
|
545
|
+
"Extension slot lookup needs the farm's pool/*.json when --slot is provided. Run it from the Farmslot checkout that holds pool/ or from a directory beside that checkout."
|
|
546
|
+
);
|
|
547
|
+
}
|
|
543
548
|
return null;
|
|
544
549
|
}
|
|
545
|
-
const poolsDir = path.join(protocolRoot, "pool");
|
|
546
550
|
if (!fs.existsSync(poolsDir)) return null;
|
|
547
551
|
const pools = poolFilesForHost(poolsDir);
|
|
548
552
|
for (const { data } of [...pools.local, ...pools.other]) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { recipeRuntimePath, shellQuote } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { spawnSync } from "node:child_process";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { defineAdapter } from "@farmslot/adapter-sdk";
|
|
5
|
+
import { runnerDir } from "../../paths.js";
|
|
5
6
|
import {
|
|
6
7
|
isExtensionWatcherLive,
|
|
7
8
|
resolveExtensionSlotPorts,
|
|
@@ -14,6 +15,7 @@ import { extensionActions } from "./actions.js";
|
|
|
14
15
|
import { extensionHarness, extensionPrepare, extensionRuntimeContext } from "./overlay.js";
|
|
15
16
|
import { extensionReadiness, extensionRuntimeDecision } from "./readiness.js";
|
|
16
17
|
import { extensionDiagnostics, extensionObservation, extensionRecording, extensionRun } from "./run.js";
|
|
18
|
+
import { checkoutHas, checkoutHasDir } from "../checkout-files.js";
|
|
17
19
|
function watcherStatus(buildLog) {
|
|
18
20
|
if (buildLog === "ok") return "up";
|
|
19
21
|
if (buildLog === "no-watch") return "down";
|
|
@@ -24,8 +26,9 @@ function extensionRuntimeNextAction(reasonCode, target) {
|
|
|
24
26
|
if (reasonCode === "rpc-execution-failed") return `mm-harness logs --target ${resolved} --full`;
|
|
25
27
|
return reasonCode === "deps-missing" || reasonCode === "deps-stale" ? `cd ${resolved} && yarn install --immutable` : `mm-harness launch --adapter extension --target ${resolved}`;
|
|
26
28
|
}
|
|
27
|
-
const extensionSurface = {
|
|
28
|
-
|
|
29
|
+
const extensionSurface = defineAdapter({
|
|
30
|
+
id: "extension",
|
|
31
|
+
sdkVersion: 1,
|
|
29
32
|
headless: false,
|
|
30
33
|
resolveSlotPorts(target) {
|
|
31
34
|
resolveExtensionSlotPorts(target);
|
|
@@ -100,6 +103,18 @@ const extensionSurface = {
|
|
|
100
103
|
appLogSource(target) {
|
|
101
104
|
return { label: "extension", path: recipeRuntimePath(target, "extension-console.log") };
|
|
102
105
|
},
|
|
106
|
+
detect: {
|
|
107
|
+
remote: (url) => url.includes("metamask-extension"),
|
|
108
|
+
files: (target) => checkoutHas(target, "development/skills-sync.ts") || checkoutHasDir(target, "ui") && checkoutHasDir(target, "app/scripts")
|
|
109
|
+
},
|
|
110
|
+
flags: {
|
|
111
|
+
launch: ["build", "watch", "verify", "sidepanel", "fullscreen"],
|
|
112
|
+
commands: ["launchExistingDist", "startWatch", "buildLavamoat"]
|
|
113
|
+
},
|
|
114
|
+
failurePatterns: {
|
|
115
|
+
walletState: /fixture|keyring|not seeded|\bsrp\b|password|onboard/iu,
|
|
116
|
+
transport: /cdp|chrome|port\b|econnrefused|not reachable|watcher|websocket/iu
|
|
117
|
+
},
|
|
103
118
|
hints: {
|
|
104
119
|
launch: "mm-harness launch",
|
|
105
120
|
relaunch: "mm-harness launch --build",
|
|
@@ -135,7 +150,7 @@ const extensionSurface = {
|
|
|
135
150
|
recording: extensionRecording,
|
|
136
151
|
diagnostics: extensionDiagnostics,
|
|
137
152
|
observation: extensionObservation
|
|
138
|
-
};
|
|
153
|
+
});
|
|
139
154
|
adapterRegistry.register(extensionSurface);
|
|
140
155
|
export {
|
|
141
156
|
extensionRuntimeNextAction,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { recipeHarnessPath, recipeHarnessRoot, recipeRuntimeDir, readRuntimeContextField, resolveRuntimeContextPath } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
2
3
|
import crypto from "node:crypto";
|
|
3
4
|
import fs from "node:fs";
|
|
4
5
|
import http from "node:http";
|
|
5
6
|
import path from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
import { recipeHarnessPath, recipeHarnessRoot, recipeRuntimeDir, runnerDir } from "../../paths.js";
|
|
7
|
+
import { runnerDir } from "../../paths.js";
|
|
8
8
|
import { resolveExtensionSlotPorts } from "../slot-ports.js";
|
|
9
9
|
const USAGE = "Usage: mm-harness verify --adapter extension -- [--target <metamask-extension>] [--out <recipes-dir>] [--cdp-port <port>] [--static-only] [--artifacts-dir <dir>]";
|
|
10
10
|
const EXTENSION_ID_PATTERN = /^[a-p]{32}$/u;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { recipeHarnessPath } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { execFileSync } from "node:child_process";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { pathToFileURL } from "node:url";
|
|
5
|
-
import {
|
|
6
|
+
import { runnerDir } from "../paths.js";
|
|
6
7
|
import { getAdapterSurface } from "./surface.js";
|
|
7
8
|
async function ensureHarnessFresh(target, adapter) {
|
|
8
9
|
if (!fs.existsSync(path.join(target, "package.json")) || !hasCheckoutHead(target)) return;
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { execFile } from "node:child_process";
|
|
2
2
|
import { promisify } from "node:util";
|
|
3
|
-
import {
|
|
4
|
-
summarizeFrames
|
|
5
|
-
} from "./frame-metrics.js";
|
|
3
|
+
import { summarizeFrames } from "@farmslot/adapter-rn";
|
|
6
4
|
const execFileAsync = promisify(execFile);
|
|
7
5
|
const POLL_INTERVAL_MS = 750;
|
|
8
6
|
const MAX_FRAMES = 1e5;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
function mobileAppIdentityEnv(env = {}) {
|
|
2
|
+
return {
|
|
3
|
+
ANDROID_PACKAGE_ID: env.ANDROID_PACKAGE_ID ?? process.env.ANDROID_PACKAGE_ID ?? "io.metamask",
|
|
4
|
+
IOS_BUNDLE_ID: env.IOS_BUNDLE_ID ?? process.env.IOS_BUNDLE_ID ?? "io.metamask.MetaMask",
|
|
5
|
+
METAMASK_RECIPE_MOBILE_APP_LABEL: env.METAMASK_RECIPE_MOBILE_APP_LABEL ?? process.env.METAMASK_RECIPE_MOBILE_APP_LABEL ?? "MetaMask"
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
mobileAppIdentityEnv
|
|
10
|
+
};
|
|
@@ -3,7 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import {
|
|
4
4
|
mobileToolRecovery,
|
|
5
5
|
resolveMobileToolPath
|
|
6
|
-
} from "
|
|
6
|
+
} from "@farmslot/adapter-rn";
|
|
7
7
|
import { runnerDir } from "../../paths.js";
|
|
8
8
|
function mobileToolDoctorChecks(platform) {
|
|
9
9
|
const specs = platform === "android" ? [{ tool: "adb", platform: "Android" }] : platform === "ios" ? [{ tool: "idb", platform: "iOS" }] : [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { EXIT, spawnScriptStreaming } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import path from "node:path";
|
|
2
|
-
import { EXIT, spawnScriptStreaming } from "../../commands/shared.js";
|
|
3
3
|
import { runnerDir } from "../../paths.js";
|
|
4
4
|
import { FIXTURE_STREAM_TIMEOUT_MS } from "../../commands/fixtures.js";
|
|
5
5
|
const FIXTURE_BRIDGE_READY_TIMEOUT_MS = 18e4;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import { recipeRuntimePath, EXIT, str, writeInteractiveProgress } from "@farmslot/recipe-cli/harness";
|
|
2
3
|
import { applyDeviceTargeting } from "../../commands/device-target.js";
|
|
3
4
|
import { launchMobile } from "../../commands/launch/mobile.js";
|
|
4
5
|
import { shellQuote } from "../../commands/launch/quote.js";
|
|
5
|
-
|
|
6
|
-
import { RECOVERY_CODE } from "../../heal-bounds.js";
|
|
7
|
-
import { recipeRuntimePath } from "../../paths.js";
|
|
6
|
+
const METRO_RESTARTED = "metro.restarted";
|
|
8
7
|
function mobileProvisioningBlocked(output) {
|
|
9
8
|
return /open-device: configured iOS simulator '.+' does not exist|open-device: no MetaMask bundle found|fast mode requires an installed (?:iOS dev client|Android dev client)/u.test(output);
|
|
10
9
|
}
|
|
@@ -17,8 +16,8 @@ function ambiguousConfiguredIosSimulator(output) {
|
|
|
17
16
|
function mobileBridgeTargetMissing(output) {
|
|
18
17
|
return /no bridge target matched|wait-for-bridge: readiness deadline expired/iu.test(output);
|
|
19
18
|
}
|
|
20
|
-
function mobileProvisionCommand(target,
|
|
21
|
-
const platform =
|
|
19
|
+
function mobileProvisionCommand(target, platformTarget) {
|
|
20
|
+
const platform = platformTarget === "android" ? "android" : "ios";
|
|
22
21
|
const device = platform === "ios" ? process.env.SIM_UDID || process.env.IOS_SIMULATOR : process.env.ADB_SERIAL || process.env.ANDROID_SERIAL || process.env.ANDROID_DEVICE;
|
|
23
22
|
const parts = ["mm-harness", "provision", "runway", platform, "--adapter", "mobile", "--target", shellQuote(target)];
|
|
24
23
|
if (device) parts.push("--device", shellQuote(device));
|
|
@@ -27,11 +26,11 @@ function mobileProvisionCommand(target, mobileTarget) {
|
|
|
27
26
|
function isIosSimulatorUdid(value) {
|
|
28
27
|
return /^[0-9A-Fa-f-]{36}$/u.test(value);
|
|
29
28
|
}
|
|
30
|
-
function launchDeviceLabel(
|
|
31
|
-
if (
|
|
29
|
+
function launchDeviceLabel(platformTarget) {
|
|
30
|
+
if (platformTarget === "android") {
|
|
32
31
|
return process.env.ANDROID_TARGET_DEVICE_NAME || process.env.ADB_SERIAL || process.env.ANDROID_SERIAL || process.env.ANDROID_DEVICE || "android device";
|
|
33
32
|
}
|
|
34
|
-
if (
|
|
33
|
+
if (platformTarget === "ios") {
|
|
35
34
|
return process.env.IOS_SIMULATOR || process.env.SIM_UDID || "iOS simulator";
|
|
36
35
|
}
|
|
37
36
|
return process.env.IOS_SIMULATOR || process.env.ADB_SERIAL || "booted device";
|
|
@@ -51,22 +50,22 @@ function metroLaunchEvidence(target) {
|
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
const mobileLaunchProfile = {
|
|
54
|
-
refuseFlags({
|
|
55
|
-
if (!
|
|
53
|
+
refuseFlags({ platformTarget }) {
|
|
54
|
+
if (!platformTarget) {
|
|
56
55
|
return { message: "target is required for mobile.", userAction: "mm-harness launch ios or mm-harness launch android" };
|
|
57
56
|
}
|
|
58
57
|
return void 0;
|
|
59
58
|
},
|
|
60
|
-
applyEnv({ adapter, options,
|
|
59
|
+
applyEnv({ adapter, options, platformTarget, target }) {
|
|
61
60
|
const device = str(options, "device");
|
|
62
|
-
if (!device &&
|
|
61
|
+
if (!device && platformTarget !== "ios" && platformTarget !== "android") return void 0;
|
|
63
62
|
const targetingOptions = {
|
|
64
63
|
...options,
|
|
65
|
-
...
|
|
64
|
+
...platformTarget ? { platform: platformTarget } : {}
|
|
66
65
|
};
|
|
67
66
|
const result = applyDeviceTargeting("launch", adapter, targetingOptions, { gate: false, rerun: "" });
|
|
68
67
|
if ("code" in result) {
|
|
69
|
-
if (
|
|
68
|
+
if (platformTarget === "ios" && result.code === "DEVICE_NOT_FOUND") {
|
|
70
69
|
process.env.IOS_SIMULATOR = device;
|
|
71
70
|
process.env.SIM_UDID = isIosSimulatorUdid(device) ? device : "";
|
|
72
71
|
process.env.ADB_SERIAL = "";
|
|
@@ -77,7 +76,7 @@ const mobileLaunchProfile = {
|
|
|
77
76
|
return result;
|
|
78
77
|
}
|
|
79
78
|
}
|
|
80
|
-
if (
|
|
79
|
+
if (platformTarget === "android" && device && !process.env.ADB_SERIAL && !process.env.ANDROID_SERIAL) {
|
|
81
80
|
return {
|
|
82
81
|
ok: false,
|
|
83
82
|
code: "DEVICE_WRONG_PLATFORM",
|
|
@@ -85,7 +84,7 @@ const mobileLaunchProfile = {
|
|
|
85
84
|
userAction: `mm-harness status --target ${shellQuote(target)} --all-devices --json`
|
|
86
85
|
};
|
|
87
86
|
}
|
|
88
|
-
if (
|
|
87
|
+
if (platformTarget === "ios" && device && !process.env.IOS_SIMULATOR) {
|
|
89
88
|
return {
|
|
90
89
|
ok: false,
|
|
91
90
|
code: "DEVICE_WRONG_PLATFORM",
|
|
@@ -95,17 +94,17 @@ const mobileLaunchProfile = {
|
|
|
95
94
|
}
|
|
96
95
|
return void 0;
|
|
97
96
|
},
|
|
98
|
-
start({ options,
|
|
99
|
-
const device = str(options, "device") ?? (
|
|
97
|
+
start({ options, platformTarget, machine, tier, wantClearMetro }) {
|
|
98
|
+
const device = str(options, "device") ?? (platformTarget === "android" ? process.env.ADB_SERIAL ?? process.env.ANDROID_SERIAL : process.env.IOS_SIMULATOR ?? process.env.SIM_UDID) ?? "configured device";
|
|
100
99
|
const watcherPort = str(options, "watcherPort") ?? process.env.WATCHER_PORT ?? "auto";
|
|
101
100
|
writeInteractiveProgress(
|
|
102
101
|
machine,
|
|
103
|
-
`\u2192 mobile launch \u2014 ${
|
|
102
|
+
`\u2192 mobile launch \u2014 ${platformTarget} \xB7 ${tier === "build" ? "native build" : "quick readiness"} \xB7 ${device} \xB7 Metro ${watcherPort === "auto" ? "auto" : `:${watcherPort}`}${wantClearMetro ? " \xB7 clear cache" : ""}`
|
|
104
103
|
);
|
|
105
104
|
},
|
|
106
105
|
nativeInputs: ["ios", "android", "package.json", "yarn.lock"],
|
|
107
|
-
rebuildCommand: ({
|
|
108
|
-
compose: ({ target,
|
|
106
|
+
rebuildCommand: ({ platformTarget }) => `mm-harness launch ${platformTarget} --build`,
|
|
107
|
+
compose: ({ target, platformTarget, machine, remoteFlagRequest }, tier, restartApp, clearMetro) => launchMobile(target, platformTarget, tier, machine, restartApp, clearMetro, remoteFlagRequest?.flags),
|
|
109
108
|
classify(_launch, output) {
|
|
110
109
|
if (output.includes("open-device: Android device is locked.")) {
|
|
111
110
|
return {
|
|
@@ -130,7 +129,7 @@ const mobileLaunchProfile = {
|
|
|
130
129
|
return void 0;
|
|
131
130
|
},
|
|
132
131
|
async beforeHeal(launch, attempt, state) {
|
|
133
|
-
const { target,
|
|
132
|
+
const { target, platformTarget, tier } = launch;
|
|
134
133
|
const output = attempt.output;
|
|
135
134
|
const missingIosSimulator = missingConfiguredIosSimulator(output);
|
|
136
135
|
const ambiguousIosSimulator = ambiguousConfiguredIosSimulator(output);
|
|
@@ -157,9 +156,9 @@ const mobileLaunchProfile = {
|
|
|
157
156
|
if (mobileProvisioningBlocked(output)) {
|
|
158
157
|
return launch.fail(state, {
|
|
159
158
|
code: "MOBILE_PROVISION_REQUIRED",
|
|
160
|
-
message: `mobile ${
|
|
159
|
+
message: `mobile ${platformTarget ?? "runtime"} is not provisioned for this slot.`,
|
|
161
160
|
recoverable: false,
|
|
162
|
-
userAction: mobileProvisionCommand(target,
|
|
161
|
+
userAction: mobileProvisionCommand(target, platformTarget),
|
|
163
162
|
exitCode: EXIT.runtime,
|
|
164
163
|
originalError: output.trim() || void 0
|
|
165
164
|
});
|
|
@@ -177,14 +176,14 @@ const mobileLaunchProfile = {
|
|
|
177
176
|
},
|
|
178
177
|
recovery(_launch, output) {
|
|
179
178
|
const restartApp = mobileBridgeTargetMissing(output);
|
|
180
|
-
return { code: restartApp ? "mobile.app-restarted" :
|
|
179
|
+
return { code: restartApp ? "mobile.app-restarted" : METRO_RESTARTED, restartApp };
|
|
181
180
|
},
|
|
182
181
|
// Mobile proved its set inside launchMobile (null: nothing requested and no
|
|
183
182
|
// runtime answered).
|
|
184
183
|
provenFlags: (_launch, requested, proven) => ({ flags: proven === void 0 ? requested : proven }),
|
|
185
|
-
verifyArgs: ({
|
|
186
|
-
platformLabel: ({
|
|
187
|
-
deviceLabel: ({
|
|
184
|
+
verifyArgs: ({ platformTarget }) => platformTarget ? ["--platform", platformTarget] : [],
|
|
185
|
+
platformLabel: ({ platformTarget }) => platformTarget ?? null,
|
|
186
|
+
deviceLabel: ({ platformTarget }) => launchDeviceLabel(platformTarget),
|
|
188
187
|
evidence: metroLaunchEvidence
|
|
189
188
|
};
|
|
190
189
|
export {
|