@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
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
bridgeCommand,
|
|
4
4
|
MOBILE_BRIDGE_ERROR_CODES
|
|
5
5
|
} from "../../../library/actions/mobile/platform/bridge.mjs";
|
|
6
|
-
import { resolveMobileToolPath } from "
|
|
6
|
+
import { resolveMobileToolPath } from "@farmslot/adapter-rn";
|
|
7
7
|
import {
|
|
8
8
|
MOBILE_LIFECYCLE_DEADLINE_FIELD,
|
|
9
9
|
MOBILE_LIFECYCLE_PREPARED
|
|
@@ -1,68 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"SEGMENT_PROXY_URL",
|
|
8
|
-
"SEGMENT_WRITE_KEY",
|
|
9
|
-
"SEGMENT_FLUSH_INTERVAL",
|
|
10
|
-
"SEGMENT_FLUSH_EVENT_LIMIT"
|
|
11
|
-
];
|
|
1
|
+
import { metroEnvCheck, metroEnvFingerprint, recordMetroEnvBaseline } from "@farmslot/adapter-rn";
|
|
2
|
+
import { recipeRuntimePath } from "@farmslot/recipe-cli/harness";
|
|
3
|
+
const MOBILE_METRO_ENV_INPUTS = {
|
|
4
|
+
files: [".js.env", ".env", ".env.local"],
|
|
5
|
+
env: ["SEGMENT_PROXY_URL", "SEGMENT_WRITE_KEY", "SEGMENT_FLUSH_INTERVAL", "SEGMENT_FLUSH_EVENT_LIMIT"]
|
|
6
|
+
};
|
|
12
7
|
const BASELINE_FILE = "metro-env-baseline.json";
|
|
13
8
|
function mobileMetroEnvFingerprint(target) {
|
|
14
|
-
|
|
15
|
-
for (const relative of ENV_INPUTS) {
|
|
16
|
-
const absolute = path.join(target, relative);
|
|
17
|
-
hash.update(`${relative}\0`);
|
|
18
|
-
if (fs.existsSync(absolute)) hash.update(fs.readFileSync(absolute));
|
|
19
|
-
else hash.update("<absent>");
|
|
20
|
-
hash.update("\0");
|
|
21
|
-
}
|
|
22
|
-
for (const name of PROCESS_ENV_INPUTS) {
|
|
23
|
-
hash.update(`${name}\0${process.env[name] ?? "<absent>"}\0`);
|
|
24
|
-
}
|
|
25
|
-
return hash.digest("hex");
|
|
9
|
+
return metroEnvFingerprint(target, MOBILE_METRO_ENV_INPUTS);
|
|
26
10
|
}
|
|
27
11
|
function mobileMetroEnvCheck(target) {
|
|
28
|
-
|
|
29
|
-
const marker = readBaseline(target);
|
|
30
|
-
return {
|
|
31
|
-
fingerprint,
|
|
32
|
-
status: marker === null ? "missing" : marker.fingerprint === fingerprint ? "current" : "changed"
|
|
33
|
-
};
|
|
12
|
+
return metroEnvCheck(target, MOBILE_METRO_ENV_INPUTS, recipeRuntimePath(target, BASELINE_FILE));
|
|
34
13
|
}
|
|
35
14
|
function recordMobileMetroEnvBaseline(target, expectedFingerprint) {
|
|
36
|
-
|
|
37
|
-
const marker = recipeRuntimePath(target, BASELINE_FILE);
|
|
38
|
-
const temporary = `${marker}.${process.pid}.${Date.now()}.tmp`;
|
|
39
|
-
const baseline = {
|
|
40
|
-
schemaVersion: 1,
|
|
41
|
-
fingerprint: expectedFingerprint,
|
|
42
|
-
recordedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
43
|
-
};
|
|
44
|
-
fs.mkdirSync(path.dirname(marker), { recursive: true });
|
|
45
|
-
try {
|
|
46
|
-
fs.writeFileSync(temporary, `${JSON.stringify(baseline, null, 2)}
|
|
47
|
-
`, { mode: 384 });
|
|
48
|
-
if (mobileMetroEnvFingerprint(target) !== expectedFingerprint) return false;
|
|
49
|
-
fs.renameSync(temporary, marker);
|
|
50
|
-
if (mobileMetroEnvFingerprint(target) !== expectedFingerprint) {
|
|
51
|
-
if (readBaseline(target)?.fingerprint === expectedFingerprint) fs.rmSync(marker, { force: true });
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
} finally {
|
|
55
|
-
fs.rmSync(temporary, { force: true });
|
|
56
|
-
}
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
function readBaseline(target) {
|
|
60
|
-
try {
|
|
61
|
-
const parsed = JSON.parse(fs.readFileSync(recipeRuntimePath(target, BASELINE_FILE), "utf8"));
|
|
62
|
-
return parsed.schemaVersion === 1 && typeof parsed.fingerprint === "string" ? parsed : null;
|
|
63
|
-
} catch {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
15
|
+
return recordMetroEnvBaseline(target, MOBILE_METRO_ENV_INPUTS, recipeRuntimePath(target, BASELINE_FILE), expectedFingerprint);
|
|
66
16
|
}
|
|
67
17
|
export {
|
|
68
18
|
mobileMetroEnvCheck,
|
|
@@ -37,7 +37,7 @@ async function markRuntime(client, name) {
|
|
|
37
37
|
}
|
|
38
38
|
function resolvePlatform(env) {
|
|
39
39
|
const explicit = String(
|
|
40
|
-
env.
|
|
40
|
+
env.RECIPE_RN_EXPLICIT_PLATFORM ?? env.RECIPE_HARNESS_PLATFORM ?? ""
|
|
41
41
|
).toLowerCase();
|
|
42
42
|
if (explicit === "android" || explicit === "ios") return explicit;
|
|
43
43
|
return env.ADB_SERIAL || env.ANDROID_SERIAL || env.ANDROID_DEVICE ? "android" : "ios";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { recipeRuntimeDir } from "
|
|
3
|
+
import { recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
|
|
4
4
|
function readRuntimeContextTarget(target) {
|
|
5
5
|
const file = path.join(target, recipeRuntimeDir(), "agentic-runtime.json");
|
|
6
6
|
let parsed;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import { EXIT, spawnScriptStreaming, shellQuote } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { execFileSync } from "node:child_process";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import { recordDepsBaseline } from "@farmslot/recipe-
|
|
4
|
-
import { resolveAndExportMobileToolPaths } from "
|
|
5
|
-
import { EXIT, spawnScriptStreaming } from "../../commands/shared.js";
|
|
6
|
-
import { shellQuote } from "../../commands/parse-args.js";
|
|
4
|
+
import { recordDepsBaseline } from "@farmslot/recipe-runner/runtime/deps-readiness";
|
|
5
|
+
import { resolveAndExportMobileToolPaths } from "@farmslot/adapter-rn";
|
|
7
6
|
import { runnerDir } from "../../paths.js";
|
|
8
7
|
import {
|
|
9
8
|
decideMobileReadiness,
|
|
@@ -401,7 +400,7 @@ async function dispatchAction(action, target, platform, json, preflightMode = "f
|
|
|
401
400
|
leaf,
|
|
402
401
|
withWatcherPort(["--target", cwd, ...extra], watcherPort),
|
|
403
402
|
target,
|
|
404
|
-
{
|
|
403
|
+
{ RECIPE_RN_METRO_ENV_FINGERPRINT: metroEnvFingerprint ?? mobileMetroEnvCheck(path.resolve(target)).fingerprint }
|
|
405
404
|
);
|
|
406
405
|
}
|
|
407
406
|
case "start-console-forwarder": {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { 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";
|
|
4
5
|
import os from "node:os";
|
|
5
6
|
import path from "node:path";
|
|
6
|
-
import { recipeRuntimeDir } from "../../paths.js";
|
|
7
7
|
import { resolveSlotPortsByRepo } from "../../../adapters/shared/resolve-slot-ports-core.mjs";
|
|
8
8
|
const RUNWAY_IOS_METADATA = {
|
|
9
9
|
artifactName: "ios-app-main-dev-expo",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { optionFlag, optionString, parsePort } from "
|
|
1
|
+
import { optionFlag, optionString, parsePort } from "@farmslot/recipe-cli/harness";
|
|
2
2
|
import { detectOrphanMetros, mobileToolDoctorChecks } from "./doctor-checks.js";
|
|
3
3
|
import { ensureMobilePerpsEnvironment, mobilePerpsEnvironment } from "./perps-env.js";
|
|
4
4
|
const mobileReadiness = {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
function resolveAndroidDeviceSerial(env = process.env) {
|
|
2
|
+
return env.ADB_SERIAL?.trim() || process.env.ADB_SERIAL?.trim() || void 0;
|
|
3
|
+
}
|
|
4
|
+
function resolveMobileIosSimulatorName(env = process.env) {
|
|
5
|
+
const explicit = env.IOS_SIMULATOR?.trim() || env.SIM_UDID?.trim();
|
|
6
|
+
if (explicit) return explicit;
|
|
7
|
+
const slot = env.FARMSLOT_SLOT_ID?.trim() || env.SLOT_ID?.trim();
|
|
8
|
+
if (!slot) return void 0;
|
|
9
|
+
const suffix = slot.includes("-") ? slot.slice(slot.lastIndexOf("-") + 1) : slot;
|
|
10
|
+
return suffix || void 0;
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
resolveAndroidDeviceSerial,
|
|
14
|
+
resolveMobileIosSimulatorName
|
|
15
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { recipeRuntimePath } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { randomBytes } from "node:crypto";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
|
-
import { recipeRuntimePath } from "../../paths.js";
|
|
5
5
|
import {
|
|
6
6
|
assertAndroidReleaseArtifactRuntime
|
|
7
7
|
} from "./release-artifact.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { EXIT, spawnScript } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import path from "node:path";
|
|
2
|
-
import { EXIT, spawnScript } from "../../commands/shared.js";
|
|
3
3
|
import { runnerDir } from "../../paths.js";
|
|
4
4
|
function reloadMobile(target, json) {
|
|
5
5
|
const script = path.join(runnerDir, "adapters/mobile/reload-app.mjs");
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
+
import { isRecord } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { spawnSync } from "node:child_process";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import {
|
|
4
|
+
import { IOS_SIMULATOR_RECORDING_TARGET_PREFIX } from "@farmslot/adapter-rn";
|
|
4
5
|
import { runnerDir } from "../../paths.js";
|
|
5
6
|
import { devicePlatformFromEnv } from "../performance/device-platform.js";
|
|
6
7
|
import {
|
|
7
|
-
IOS_SIMULATOR_RECORDING_TARGET_PREFIX,
|
|
8
8
|
resolveAndroidDeviceSerial,
|
|
9
9
|
resolveMobileIosSimulatorName
|
|
10
|
-
} from "
|
|
10
|
+
} from "./recording-target.js";
|
|
11
|
+
import { mobileAppIdentityEnv } from "./app-identity.js";
|
|
11
12
|
import { requireCurrentMobileReleaseArtifactState } from "./release-artifact-state.js";
|
|
12
13
|
const EXPLICIT_DEVICE_KEYS = [
|
|
13
14
|
"PLATFORM",
|
|
14
|
-
"
|
|
15
|
+
"RECIPE_RN_EXPLICIT_PLATFORM",
|
|
15
16
|
"IOS_SIMULATOR",
|
|
16
17
|
"SIM_UDID",
|
|
17
18
|
"ADB_SERIAL",
|
|
@@ -21,7 +22,7 @@ const EXPLICIT_DEVICE_KEYS = [
|
|
|
21
22
|
];
|
|
22
23
|
const mobileRun = {
|
|
23
24
|
pinnedEnv() {
|
|
24
|
-
if (!process.env.
|
|
25
|
+
if (!process.env.RECIPE_RN_EXPLICIT_PLATFORM) return void 0;
|
|
25
26
|
return Object.fromEntries(EXPLICIT_DEVICE_KEYS.map((key) => [key, process.env[key]]));
|
|
26
27
|
},
|
|
27
28
|
envKeys: ["METAMASK_RECIPE_MOBILE_OPAQUE_RUNTIME", "ANDROID_PACKAGE_ID", "ADB_SERIAL", "ANDROID_SERIAL"],
|
|
@@ -49,7 +50,7 @@ const mobileRun = {
|
|
|
49
50
|
ANDROID_TARGET_DEVICE_NAME: process.env.ANDROID_TARGET_DEVICE_NAME,
|
|
50
51
|
ADB_SERIAL: process.env.ADB_SERIAL,
|
|
51
52
|
ANDROID_SERIAL: process.env.ANDROID_SERIAL,
|
|
52
|
-
|
|
53
|
+
...mobileAppIdentityEnv(),
|
|
53
54
|
METAMASK_RECIPE_MOBILE_OPAQUE_RUNTIME: process.env.METAMASK_RECIPE_MOBILE_OPAQUE_RUNTIME
|
|
54
55
|
}),
|
|
55
56
|
// An installed release artifact is opaque: no harness HUD inside it.
|
|
@@ -78,9 +79,9 @@ const mobileRecording = {
|
|
|
78
79
|
const androidSerial = resolveAndroidDeviceSerial();
|
|
79
80
|
const iosSimulator = androidSerial ? void 0 : resolveMobileIosSimulatorName();
|
|
80
81
|
if (!androidSerial && !iosSimulator) return void 0;
|
|
81
|
-
const { createAndroidVideoRecorder, createIosSimulatorVideoRecorder } = await import("
|
|
82
|
+
const { createAndroidVideoRecorder, createIosSimulatorVideoRecorder } = await import("@farmslot/adapter-rn");
|
|
82
83
|
if (androidSerial) {
|
|
83
|
-
const { createAndroidMirrorVideoRecorder } = await import("@farmslot/recipe-
|
|
84
|
+
const { createAndroidMirrorVideoRecorder } = await import("@farmslot/recipe-runner");
|
|
84
85
|
return createAndroidMirrorVideoRecorder({ serial: androidSerial, fallback: createAndroidVideoRecorder(androidSerial) });
|
|
85
86
|
}
|
|
86
87
|
return createIosSimulatorVideoRecorder(iosSimulator);
|
|
@@ -5,16 +5,14 @@ import path from "node:path";
|
|
|
5
5
|
import {
|
|
6
6
|
depsCheck,
|
|
7
7
|
recordDepsBaseline
|
|
8
|
-
} from "@farmslot/recipe-
|
|
8
|
+
} from "@farmslot/recipe-runner/runtime/deps-readiness";
|
|
9
9
|
import {
|
|
10
10
|
analyzeBundleLog,
|
|
11
11
|
supersededErrorCapture
|
|
12
|
-
} from "@farmslot/recipe-
|
|
13
|
-
import { probeMetroPackager } from "@farmslot/recipe-
|
|
14
|
-
import { color } from "
|
|
15
|
-
import {
|
|
16
|
-
import { recipeRuntimePath } from "../../paths.js";
|
|
17
|
-
import { resolveMobileToolPath } from "../../../library/actions/mobile/platform/tool-paths.mjs";
|
|
12
|
+
} from "@farmslot/recipe-runner/runtime/log-analysis";
|
|
13
|
+
import { probeMetroPackager } from "@farmslot/recipe-runner/runtime/metro-probe";
|
|
14
|
+
import { color, recipeRuntimePath, shellQuote } from "@farmslot/recipe-cli/harness";
|
|
15
|
+
import { resolveMobileToolPath } from "@farmslot/adapter-rn";
|
|
18
16
|
import { mobileProductMarkers } from "./deps-markers.js";
|
|
19
17
|
import { mobileMetroEnvCheck } from "./metro-env.js";
|
|
20
18
|
const BUNDLE_ERR = /Bundling failed|Unable to resolve /u;
|
|
@@ -1,135 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
const ENV_INPUTS = [".js.env", ".env", ".env.local"];
|
|
1
|
+
import { recordSourceBaseline, sourceCheck, sourceFingerprint } from "@farmslot/adapter-rn";
|
|
2
|
+
import { recipeRuntimePath } from "@farmslot/recipe-cli/harness";
|
|
3
|
+
const MOBILE_SOURCE_INPUTS = {
|
|
4
|
+
paths: [
|
|
5
|
+
"app",
|
|
6
|
+
"locales",
|
|
7
|
+
"index.js",
|
|
8
|
+
"shim.js",
|
|
9
|
+
"shimPerf.js",
|
|
10
|
+
"ReactotronConfig.js",
|
|
11
|
+
"wdyr.js",
|
|
12
|
+
"app.config.js",
|
|
13
|
+
"babel.config.js",
|
|
14
|
+
"metro.config.js",
|
|
15
|
+
"metro.transform.js",
|
|
16
|
+
"package.json"
|
|
17
|
+
],
|
|
18
|
+
envFiles: [".js.env", ".env", ".env.local"]
|
|
19
|
+
};
|
|
21
20
|
const BASELINE_FILE = "mobile-source-baseline.json";
|
|
22
21
|
function mobileSourceFingerprint(target) {
|
|
23
|
-
|
|
24
|
-
const head = tryGit(target, ["rev-parse", "HEAD"]);
|
|
25
|
-
if (head === null) {
|
|
26
|
-
hash.update("non-git\0");
|
|
27
|
-
for (const relative of SOURCE_PATHS) {
|
|
28
|
-
hashPath(hash, target, relative);
|
|
29
|
-
}
|
|
30
|
-
} else {
|
|
31
|
-
hash.update(head);
|
|
32
|
-
hash.update(git(target, ["diff", "--no-ext-diff", "--binary", "HEAD", "--", ...SOURCE_PATHS]));
|
|
33
|
-
const untracked = git(target, [
|
|
34
|
-
"ls-files",
|
|
35
|
-
"--others",
|
|
36
|
-
"--exclude-standard",
|
|
37
|
-
"-z",
|
|
38
|
-
"--",
|
|
39
|
-
...SOURCE_PATHS
|
|
40
|
-
]).toString("utf8").split("\0").filter(Boolean).sort();
|
|
41
|
-
for (const relative of untracked) {
|
|
42
|
-
hash.update(`untracked\0${relative}\0`);
|
|
43
|
-
hash.update(fs.readFileSync(path.join(target, relative)));
|
|
44
|
-
hash.update("\0");
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
for (const relative of ENV_INPUTS) {
|
|
48
|
-
const absolute = path.join(target, relative);
|
|
49
|
-
hash.update(`env\0${relative}\0`);
|
|
50
|
-
hash.update(fs.existsSync(absolute) ? fs.readFileSync(absolute) : "<absent>");
|
|
51
|
-
hash.update("\0");
|
|
52
|
-
}
|
|
53
|
-
return hash.digest("hex");
|
|
22
|
+
return sourceFingerprint(target, MOBILE_SOURCE_INPUTS);
|
|
54
23
|
}
|
|
55
24
|
function mobileSourceCheck(target) {
|
|
56
|
-
|
|
57
|
-
const baseline = readBaseline(target);
|
|
58
|
-
return {
|
|
59
|
-
fingerprint,
|
|
60
|
-
status: baseline === null ? "missing" : baseline.fingerprint === fingerprint ? "current" : "changed"
|
|
61
|
-
};
|
|
25
|
+
return sourceCheck(target, MOBILE_SOURCE_INPUTS, recipeRuntimePath(target, BASELINE_FILE));
|
|
62
26
|
}
|
|
63
27
|
function recordMobileSourceBaseline(target, expectedFingerprint) {
|
|
64
|
-
|
|
65
|
-
const marker = recipeRuntimePath(target, BASELINE_FILE);
|
|
66
|
-
const temporary = `${marker}.${process.pid}.${Date.now()}.tmp`;
|
|
67
|
-
const baseline = {
|
|
68
|
-
schemaVersion: 1,
|
|
69
|
-
fingerprint: expectedFingerprint,
|
|
70
|
-
recordedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
71
|
-
};
|
|
72
|
-
fs.mkdirSync(path.dirname(marker), { recursive: true });
|
|
73
|
-
try {
|
|
74
|
-
fs.writeFileSync(temporary, `${JSON.stringify(baseline, null, 2)}
|
|
75
|
-
`, { mode: 384 });
|
|
76
|
-
if (mobileSourceFingerprint(target) !== expectedFingerprint) return false;
|
|
77
|
-
fs.renameSync(temporary, marker);
|
|
78
|
-
if (mobileSourceFingerprint(target) !== expectedFingerprint) {
|
|
79
|
-
if (readBaseline(target)?.fingerprint === expectedFingerprint) fs.rmSync(marker, { force: true });
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
} finally {
|
|
83
|
-
fs.rmSync(temporary, { force: true });
|
|
84
|
-
}
|
|
85
|
-
return true;
|
|
86
|
-
}
|
|
87
|
-
function git(target, args) {
|
|
88
|
-
return execFileSync("git", args, {
|
|
89
|
-
cwd: target,
|
|
90
|
-
encoding: "buffer",
|
|
91
|
-
maxBuffer: 128 * 1024 * 1024,
|
|
92
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
function tryGit(target, args) {
|
|
96
|
-
try {
|
|
97
|
-
return git(target, args);
|
|
98
|
-
} catch {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
function hashPath(hash, root, relative) {
|
|
103
|
-
const absolute = path.join(root, relative);
|
|
104
|
-
if (!fs.existsSync(absolute)) {
|
|
105
|
-
hash.update(`absent\0${relative}\0`);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
const stat = fs.lstatSync(absolute);
|
|
109
|
-
if (stat.isDirectory()) {
|
|
110
|
-
hash.update(`directory\0${relative}\0`);
|
|
111
|
-
for (const child of fs.readdirSync(absolute).sort()) {
|
|
112
|
-
hashPath(hash, root, path.join(relative, child));
|
|
113
|
-
}
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
if (stat.isSymbolicLink()) {
|
|
117
|
-
hash.update(`symlink\0${relative}\0${fs.readlinkSync(absolute)}\0`);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
hash.update(`file\0${relative}\0`);
|
|
121
|
-
hash.update(fs.readFileSync(absolute));
|
|
122
|
-
hash.update("\0");
|
|
123
|
-
}
|
|
124
|
-
function readBaseline(target) {
|
|
125
|
-
try {
|
|
126
|
-
const parsed = JSON.parse(
|
|
127
|
-
fs.readFileSync(recipeRuntimePath(target, BASELINE_FILE), "utf8")
|
|
128
|
-
);
|
|
129
|
-
return parsed.schemaVersion === 1 && typeof parsed.fingerprint === "string" ? parsed : null;
|
|
130
|
-
} catch {
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
28
|
+
return recordSourceBaseline(target, MOBILE_SOURCE_INPUTS, recipeRuntimePath(target, BASELINE_FILE), expectedFingerprint);
|
|
133
29
|
}
|
|
134
30
|
export {
|
|
135
31
|
mobileSourceCheck,
|
|
@@ -1,24 +1,26 @@
|
|
|
1
|
+
import { recipeRuntimePath, shellQuote, writeInteractiveProgress } 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 { resolveMobileSlotPorts } from "../slot-ports.js";
|
|
6
7
|
import { mobileRuntimeStatus } from "./prepare.js";
|
|
7
8
|
import { hasRunwayProvisionBaseline, provisionRunwayMobile } from "./provision.js";
|
|
8
9
|
import { adapterRegistry } from "../registry.js";
|
|
9
|
-
import { writeInteractiveProgress } from "../../commands/shared.js";
|
|
10
10
|
import { mobileActions } from "./actions.js";
|
|
11
11
|
import { mobileHarness, mobilePrepare, mobileRuntimeContext } from "./overlay.js";
|
|
12
12
|
import { mobileReadiness, mobileRuntimeDecision } from "./readiness.js";
|
|
13
13
|
import { clearMobileReleaseArtifactState } from "./release-artifact-state.js";
|
|
14
14
|
import { mobileDiagnostics, mobileObservation, mobileRecording, mobileRun } from "./run.js";
|
|
15
15
|
import { mobileSourceFingerprint } from "./source-freshness.js";
|
|
16
|
+
import { checkoutHas, checkoutHasDir } from "../checkout-files.js";
|
|
16
17
|
function mobileRuntimeNextAction(reasonCode, target, platform) {
|
|
17
18
|
const resolved = shellQuote(path.resolve(target));
|
|
18
19
|
return reasonCode === "deps-missing" || reasonCode === "deps-partial" || reasonCode === "deps-stale" ? `cd ${resolved} && yarn setup` : `mm-harness launch ${platform} --adapter mobile --target ${resolved}`;
|
|
19
20
|
}
|
|
20
|
-
const mobileSurface = {
|
|
21
|
-
|
|
21
|
+
const mobileSurface = defineAdapter({
|
|
22
|
+
id: "mobile",
|
|
23
|
+
sdkVersion: 1,
|
|
22
24
|
headless: false,
|
|
23
25
|
resolveSlotPorts(target) {
|
|
24
26
|
resolveMobileSlotPorts(target);
|
|
@@ -51,6 +53,9 @@ const mobileSurface = {
|
|
|
51
53
|
devServer: {
|
|
52
54
|
label: "metro",
|
|
53
55
|
describe: () => "Metro dev server",
|
|
56
|
+
// Metro's leaves read the port as METRO_PORT; run and call take it as --metro-port.
|
|
57
|
+
portEnv: ["METRO_PORT"],
|
|
58
|
+
portFlags: ["metroPort"],
|
|
54
59
|
stop(target) {
|
|
55
60
|
const leaf = path.join(runnerDir, "adapters", "mobile", "stop-metro.sh");
|
|
56
61
|
const args = ["--target", target];
|
|
@@ -68,6 +73,26 @@ const mobileSurface = {
|
|
|
68
73
|
appLogSource(target) {
|
|
69
74
|
return { label: "app", path: recipeRuntimePath(target, "app-console.log") };
|
|
70
75
|
},
|
|
76
|
+
detect: {
|
|
77
|
+
remote: (url) => url.includes("metamask-mobile"),
|
|
78
|
+
files: (target) => checkoutHas(target, "scripts/skills-sync.mts") || checkoutHasDir(target, "ios") && checkoutHasDir(target, "android") && checkoutHasDir(target, "app/core")
|
|
79
|
+
},
|
|
80
|
+
// `launch ios|android`, and --platform ios|android, select Mobile.
|
|
81
|
+
targets: ["ios", "android"],
|
|
82
|
+
flags: {
|
|
83
|
+
launch: ["build", "watch", "verify", "runway", "clearMetro"],
|
|
84
|
+
commands: ["clearMetro", "resolveOnly"]
|
|
85
|
+
},
|
|
86
|
+
failurePatterns: {
|
|
87
|
+
captureProtected: {
|
|
88
|
+
pattern: /SCREENSHOT_PROTECTED|screenshot is protected by FLAG_SECURE/iu,
|
|
89
|
+
message: "the focused Android window intentionally blocks screenshots; a black capture cannot be used as evidence.",
|
|
90
|
+
userAction: "unlock or navigate to a non-protected screen, then rerun the screenshot action"
|
|
91
|
+
},
|
|
92
|
+
transportFirst: /CDP_TIMEOUT|Mobile CDP bridge command timed out|NO_TARGET|WS_CLOSED/iu,
|
|
93
|
+
walletState: /fixture|keyring|not seeded|\bsrp\b|password|onboard/iu,
|
|
94
|
+
transport: /metro|bridge|bundle|packager|dev client/iu
|
|
95
|
+
},
|
|
71
96
|
hints: {
|
|
72
97
|
launch: "mm-harness launch ios",
|
|
73
98
|
relaunch: "mm-harness launch ios",
|
|
@@ -104,7 +129,7 @@ const mobileSurface = {
|
|
|
104
129
|
diagnostics: mobileDiagnostics,
|
|
105
130
|
observation: mobileObservation,
|
|
106
131
|
sourceFingerprint: (root) => mobileSourceFingerprint(root)
|
|
107
|
-
};
|
|
132
|
+
});
|
|
108
133
|
adapterRegistry.register(mobileSurface);
|
|
109
134
|
export {
|
|
110
135
|
mobileRuntimeNextAction,
|
|
@@ -3,9 +3,13 @@ import { promisify } from "node:util";
|
|
|
3
3
|
import { bridgeCommand, evalAsync, evalSync, MOBILE_BRIDGE_ERROR_CODES, selectBridgeStatusEntry, simulatorScreenshot } from "../../../library/actions/mobile/platform/bridge.mjs";
|
|
4
4
|
import { observeNativeUi } from "../../../library/actions/mobile/platform/observe-ui.mjs";
|
|
5
5
|
import { nativeAgentDeviceStateDir } from "../../../library/actions/mobile/platform/native-session-name.mjs";
|
|
6
|
-
import { resolveMobileToolPath } from "
|
|
6
|
+
import { resolveMobileToolPath } from "@farmslot/adapter-rn";
|
|
7
7
|
import { isRecord, traceText } from "../../action-values.js";
|
|
8
|
-
import { runLiveAdapterScript } from "
|
|
8
|
+
import { runLiveAdapterScript } from "@farmslot/recipe-cli/harness";
|
|
9
|
+
import { trustedMutationContextExtras } from "../../funding-execution-context.js";
|
|
10
|
+
import { LIBRARY_ACTION_NAMESPACE } from "../../paths.js";
|
|
11
|
+
import { liveTsxCandidates } from "../../live-tsx.js";
|
|
12
|
+
import { mobileAppIdentityEnv } from "./app-identity.js";
|
|
9
13
|
const execFileAsync = promisify(execFile);
|
|
10
14
|
function sleep(ms) {
|
|
11
15
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -213,7 +217,10 @@ async function sendMobileBridgeCommand(command, context) {
|
|
|
213
217
|
if (!handler) {
|
|
214
218
|
throw new Error(`React Native bridge command ${command.command} is not implemented by the MetaMask runner transport.`);
|
|
215
219
|
}
|
|
216
|
-
return handler(command.payload,
|
|
220
|
+
return handler(command.payload, {
|
|
221
|
+
...context,
|
|
222
|
+
env: { ...context.env, ...mobileAppIdentityEnv(context.env) }
|
|
223
|
+
});
|
|
217
224
|
}
|
|
218
225
|
function mobileUiInput(context, command, payload) {
|
|
219
226
|
return uiInputFor(context, { action: `ui.${command}`, node: payload });
|
|
@@ -235,8 +242,11 @@ async function handleMobileNavigate(payload, context) {
|
|
|
235
242
|
const live = await runLiveAdapterScript({
|
|
236
243
|
platform: "mobile",
|
|
237
244
|
action: "ui.navigate",
|
|
245
|
+
namespace: LIBRARY_ACTION_NAMESPACE,
|
|
238
246
|
node: payload,
|
|
239
|
-
context
|
|
247
|
+
context,
|
|
248
|
+
contextExtras: trustedMutationContextExtras(context),
|
|
249
|
+
tsxCandidates: liveTsxCandidates()
|
|
240
250
|
});
|
|
241
251
|
if (!live) throw new Error("ui.navigate requires library/actions/mobile/ui/navigate.mjs.");
|
|
242
252
|
return isRecord(live.result) ? { ...live.result, liveAdapter: live.script } : live.result;
|
|
@@ -586,7 +596,8 @@ async function executeNativeProviderAction(action, node, context, createTranspor
|
|
|
586
596
|
if (platform === "android" && action === "ui.swipe" && isCoordinateTarget(node.target)) {
|
|
587
597
|
return executeAndroidCoordinateSwipe(node, String(device));
|
|
588
598
|
}
|
|
589
|
-
const
|
|
599
|
+
const identity = mobileAppIdentityEnv(context.env);
|
|
600
|
+
const app = platform === "android" ? identity.ANDROID_PACKAGE_ID : identity.IOS_BUNDLE_ID;
|
|
590
601
|
const session = (platform === "ios" ? `mm-harness-${process.pid}-${device}` : `mm-harness-${process.pid}-${context.nodeId}`).replace(/[^a-zA-Z0-9._-]/gu, "-");
|
|
591
602
|
const stateDir = nativeAgentDeviceStateDir(context.env ?? {}, context.projectRoot, String(device));
|
|
592
603
|
let transport;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { recipeHarnessPath, recipeHarnessRoot, recipeRuntimeDir, spawnScriptStreaming, readRuntimeContextField } 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";
|
|
4
5
|
import path from "node:path";
|
|
5
|
-
import {
|
|
6
|
-
import { readRuntimeContextField } from "../../harness.js";
|
|
7
|
-
import { recipeHarnessPath, recipeHarnessRoot, recipeRuntimeDir, runnerDir } from "../../paths.js";
|
|
6
|
+
import { runnerDir } from "../../paths.js";
|
|
8
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]";
|
|
9
8
|
const ENV_FILES = [".js.env", ".env", ".env.local"];
|
|
10
9
|
const PREFLIGHT_MODES = ["fast", "auto", "default", "rebuild-native", "clean"];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
function devicePlatformFromEnv(env) {
|
|
2
2
|
const explicit = String(
|
|
3
|
-
env.
|
|
3
|
+
env.RECIPE_RN_EXPLICIT_PLATFORM ?? env.RECIPE_HARNESS_PLATFORM ?? ""
|
|
4
4
|
).toLowerCase();
|
|
5
5
|
if (explicit === "android" || explicit === "ios") return explicit;
|
|
6
6
|
return env.ADB_SERIAL || env.ANDROID_SERIAL || env.ANDROID_DEVICE ? "android" : "ios";
|
|
@@ -1,17 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
const adapterRegistry =
|
|
3
|
-
register(surface) {
|
|
4
|
-
if (surfaces.has(surface.adapter)) throw new Error(`adapter '${surface.adapter}' is already registered`);
|
|
5
|
-
surfaces.set(surface.adapter, surface);
|
|
6
|
-
},
|
|
7
|
-
get(id) {
|
|
8
|
-
const surface = surfaces.get(id);
|
|
9
|
-
if (!surface) throw new Error(`unknown adapter '${id}' (registered: ${adapterRegistry.list().join(", ")})`);
|
|
10
|
-
return surface;
|
|
11
|
-
},
|
|
12
|
-
has: (id) => surfaces.has(id),
|
|
13
|
-
list: () => [...surfaces.keys()]
|
|
14
|
-
};
|
|
1
|
+
import { createAdapterRegistry } from "@farmslot/adapter-sdk";
|
|
2
|
+
const adapterRegistry = createAdapterRegistry();
|
|
15
3
|
export {
|
|
16
4
|
adapterRegistry
|
|
17
5
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { execFileSync } from "node:child_process";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
|
-
import { recipeRuntimeDir } from "../paths.js";
|
|
6
6
|
import {
|
|
7
7
|
formatExtensionIdentityPorts,
|
|
8
8
|
resolveDefaultExtensionPorts,
|
package/dist/adapters/surface.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { recipeRuntimePath } from "@farmslot/recipe-cli/harness";
|
|
3
4
|
import { verifyCapture } from "../../../library/actions/shared/console-collector.mjs";
|
|
4
|
-
import { recipeRuntimePath } from "../../paths.js";
|
|
5
5
|
import { ensureConsoleCollector } from "../console-capture.js";
|
|
6
6
|
const TERMINAL_CONSOLE_FILES = Object.freeze({
|
|
7
7
|
app: "app-console.log",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { flag, str } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { execFileSync } from "node:child_process";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import { flag, str } from "../../commands/shared.js";
|
|
4
4
|
import { runnerDir } from "../../paths.js";
|
|
5
5
|
const TERMINAL_ONLY_LAUNCH_OPTIONS = Object.freeze({
|
|
6
6
|
signer: "--signer",
|