@deeeed/metamask-harness 0.79.0 → 0.81.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 +73 -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 +16 -64
- 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/harness-source-fingerprint.mjs +13 -8
- package/adapters/shared/open-debug.mjs +2 -2
- 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/launch.mjs +17 -13
- package/adapters/terminal/lib/mainnet-guard.mjs +9 -0
- package/adapters/terminal/lib/readiness.mjs +20 -12
- package/adapters/terminal/policy.mjs +35 -0
- package/adapters/terminal/verify.mjs +10 -3
- package/adapters/terminal/wallet-host.mjs +43 -225
- 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 +8 -4
- package/dist/adapters/core/overlay.js +1 -1
- package/dist/adapters/core/readiness.js +28 -1
- package/dist/adapters/core/run.js +2 -2
- package/dist/adapters/core/surface.js +16 -1
- package/dist/adapters/extension/actions.js +6 -2
- 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 +14 -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 +135 -14
- package/dist/adapters/extension/runtime-decision.js +2 -1
- package/dist/adapters/extension/runtime.js +9 -5
- package/dist/adapters/extension/surface.js +15 -2
- package/dist/adapters/extension/verify.js +2 -2
- package/dist/adapters/harness-freshness.js +2 -1
- package/dist/adapters/mobile/actions.js +4 -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/network-observer.js +68 -0
- package/dist/adapters/mobile/performance-observer.js +2 -4
- package/dist/adapters/mobile/prepare-target.js +1 -1
- package/dist/adapters/mobile/prepare.js +3 -4
- 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 +39 -15
- package/dist/adapters/mobile/runtime-decision.js +2 -4
- package/dist/adapters/mobile/source-freshness.js +22 -126
- package/dist/adapters/mobile/surface.js +26 -3
- 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/perps-order-inputs.js +36 -0
- package/dist/adapters/proof-failure.js +11 -0
- package/dist/adapters/slot-ports.js +1 -1
- package/dist/adapters/surface.js +1 -0
- package/dist/adapters/terminal/actions.js +4 -1
- package/dist/adapters/terminal/console-capture.js +1 -1
- package/dist/adapters/terminal/doctor-checks.js +2 -0
- package/dist/adapters/terminal/launch.js +4 -1
- package/dist/adapters/terminal/overlay.js +8 -1
- package/dist/adapters/terminal/run.js +33 -5
- package/dist/adapters/terminal/surface.js +9 -1
- package/dist/adapters.js +27 -7
- package/dist/advisor-policy.js +1 -1
- package/dist/checkout-view.js +1 -2
- package/dist/cli.js +59 -21
- package/dist/command-contract.js +1 -26
- package/dist/commands/check.js +33 -10
- package/dist/commands/checklist.js +1 -1
- package/dist/commands/completion-candidates.js +6 -14
- 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 +2 -8
- package/dist/commands/launch/mobile.js +1 -1
- package/dist/commands/logs.js +3 -3
- 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 +4 -9
- 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/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 +5 -8
- 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/doctor.js +2 -3
- package/dist/engine.js +57 -0
- package/dist/funding-execution-context.js +96 -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 +4 -6
- package/dist/paths.js +34 -64
- package/dist/performance-observation.js +3 -5
- package/dist/progress.js +1 -1
- package/dist/recipe-assistance-context.js +6 -9
- package/dist/recipe-security.js +2 -59
- package/dist/review/knowledge.js +2 -2
- package/dist/runner.js +7 -4
- package/dist/runtime-context.js +1 -1
- package/dist/task-view.js +2 -3
- package/docs/CONTRIBUTING.md +5 -3
- package/docs/RECIPES.md +31 -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 -134
- 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 +61 -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/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 +73 -11
- package/library/actions/harness-exports.mjs +1 -6
- package/library/actions/mobile/app/network-control.mjs +6 -8
- package/library/actions/mobile/perps/perps.mjs +216 -11
- package/library/actions/mobile/perps/place_order.mjs +3 -1
- 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/shared/perps/order-policy.mjs +177 -0
- package/library/actions/shared/wallet/fixture-accounts.mjs +84 -0
- package/library/actions/terminal/app/launch.mjs +3 -2
- package/library/actions/terminal/platform/hud.mjs +2 -1
- package/library/actions/terminal/platform/page.mjs +2 -1
- package/library/actions/terminal/platform/runtime.mjs +2 -1
- package/library/actions/terminal/wallet/_signature-log.mjs +40 -161
- package/library/actions/terminal/wallet/assert_signatures.mjs +6 -12
- package/library/actions/terminal/wallet/read_signatures.mjs +10 -9
- package/library/manifests/core.action-manifest.json +87 -13
- package/library/manifests/extension.action-manifest.json +4 -0
- package/library/manifests/mobile.action-manifest.json +12 -0
- package/package.json +8 -9
- package/site/assets/help-recipes.json +1 -0
- 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/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/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/call.js +0 -685
- package/dist/commands/last.js +0 -60
- package/dist/commands/launch/index.js +0 -109
- package/dist/commands/list-executables.js +0 -247
- package/dist/commands/manifest.js +0 -488
- package/dist/commands/parse-args.js +0 -279
- package/dist/commands/reload.js +0 -41
- package/dist/commands/run-engine.js +0 -1340
- package/dist/commands/run-report.js +0 -241
- package/dist/commands/run.js +0 -751
- package/dist/commands/shared.js +0 -323
- package/dist/commands/stop.js +0 -60
- package/dist/devices.js +0 -100
- package/dist/discovery.js +0 -15
- 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/metamask-action-validation.js +0 -68
- package/dist/network-observation.js +0 -290
- 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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { manifestPath } from "../../paths.js";
|
|
2
|
+
import { perpsOrderInputFindings } from "../perps-order-inputs.js";
|
|
2
3
|
import { extensionActionInputFindings } from "./action-inputs.js";
|
|
3
4
|
const extensionActions = {
|
|
4
5
|
manifestPath: () => manifestPath("extension"),
|
|
@@ -43,8 +44,11 @@ const extensionActions = {
|
|
|
43
44
|
})
|
|
44
45
|
}),
|
|
45
46
|
trustedMutation: true,
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
// ensure_positions and ensure_orders only check state here.
|
|
48
|
+
inputFindings: (nodeId, node) => [
|
|
49
|
+
...extensionActionInputFindings(nodeId, node),
|
|
50
|
+
...perpsOrderInputFindings(nodeId, node, { ensureChecksOnly: true })
|
|
51
|
+
]
|
|
48
52
|
};
|
|
49
53
|
export {
|
|
50
54
|
extensionActions
|
|
@@ -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
1
|
import path from "node:path";
|
|
2
|
-
import brokerModule from "
|
|
2
|
+
import brokerModule from "@farmslot/recipe-runner/cdp-broker";
|
|
3
3
|
import {
|
|
4
4
|
asBrowserCdpTarget,
|
|
5
5
|
createBrowserCdpClient,
|
|
@@ -204,6 +204,19 @@ async function waitForSocket(socketPath) {
|
|
|
204
204
|
}
|
|
205
205
|
throw new Error("Extension network observer broker did not start.");
|
|
206
206
|
}
|
|
207
|
+
async function createExtensionNetworkBackend(env, artifactsDir) {
|
|
208
|
+
return createExtensionNetworkObserver(extensionCdpPort(env), artifactsDir);
|
|
209
|
+
}
|
|
210
|
+
function extensionCdpPort(env) {
|
|
211
|
+
const port = Number(
|
|
212
|
+
env.CDP_PORT ?? env.RECIPE_CDP_PORT ?? process.env.CDP_PORT
|
|
213
|
+
);
|
|
214
|
+
if (!Number.isInteger(port) || port <= 0) {
|
|
215
|
+
throw new Error("Extension network observation requires CDP_PORT.");
|
|
216
|
+
}
|
|
217
|
+
return port;
|
|
218
|
+
}
|
|
207
219
|
export {
|
|
220
|
+
createExtensionNetworkBackend,
|
|
208
221
|
createExtensionNetworkObserver
|
|
209
222
|
};
|
|
@@ -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,15 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { EXIT, optionFlag, optionString } from "@farmslot/recipe-cli/harness";
|
|
3
|
+
import { verifyOwnedCollectorControl } from "../console-capture.js";
|
|
4
|
+
import { resolveExtensionBrowserPid } from "./browser-pid.js";
|
|
3
5
|
import {
|
|
4
6
|
ensureExtensionConsoleCapture,
|
|
5
7
|
extensionCaptureFiles,
|
|
6
8
|
extensionCdpPort,
|
|
7
9
|
verifyExtensionConsoleControl
|
|
8
10
|
} from "./console-capture.js";
|
|
11
|
+
import { emitProofFailure } from "../proof-failure.js";
|
|
9
12
|
import { launchedBrowser } from "./launched-browser.js";
|
|
13
|
+
const AUTOLAUNCH_ENV = "METAMASK_RECIPE_EXTENSION_AUTOLAUNCH";
|
|
10
14
|
const extensionRun = {
|
|
15
|
+
platformOptions: (options) => ({ launchExistingDist: optionFlag(options, "launchExistingDist") }),
|
|
16
|
+
activateEnv(_projectRoot, options) {
|
|
17
|
+
if (options.platform?.launchExistingDist) process.env[AUTOLAUNCH_ENV] = "1";
|
|
18
|
+
},
|
|
19
|
+
envKeys: [AUTOLAUNCH_ENV],
|
|
11
20
|
async prepareRuntime(projectRoot, runtimeOptions) {
|
|
12
|
-
if (runtimeOptions.skipExtensionRuntimePrepare === true) return;
|
|
21
|
+
if (runtimeOptions.platform?.skipExtensionRuntimePrepare === true) return;
|
|
13
22
|
const { releaseArtifactState, runtimeDistCheck } = await import("./runtime-decision.js");
|
|
14
23
|
const artifact = releaseArtifactState(projectRoot);
|
|
15
24
|
const runtimeSnapshot = runtimeDistCheck(projectRoot, artifact);
|
|
@@ -24,7 +33,7 @@ const extensionRun = {
|
|
|
24
33
|
projectRoot,
|
|
25
34
|
cdpPort: runtimeOptions.cdpPort,
|
|
26
35
|
slot: runtimeOptions.slot,
|
|
27
|
-
launchExistingDist: runtimeOptions.launchExistingDist === true,
|
|
36
|
+
launchExistingDist: runtimeOptions.platform?.launchExistingDist === true,
|
|
28
37
|
validationRuntimeDir: runtimeOptions.validationRuntimeDir,
|
|
29
38
|
pageMode: "home-or-sidepanel"
|
|
30
39
|
});
|
|
@@ -33,19 +42,17 @@ const extensionRun = {
|
|
|
33
42
|
// the slot's for the check, and the slot's come back afterwards.
|
|
34
43
|
runtimeCheck({ target, options, heal, state, json, onRecovery }) {
|
|
35
44
|
return async () => {
|
|
36
|
-
const cliOptions = options;
|
|
37
45
|
const previousCdpPort = process.env.CDP_PORT;
|
|
38
46
|
const previousRecipeCdpPort = process.env.RECIPE_CDP_PORT;
|
|
39
47
|
const previousWatcherPort = process.env.WATCHER_PORT;
|
|
40
|
-
const explicitCdpPort = optionString(
|
|
41
|
-
const explicitWatcherPort = optionString(
|
|
48
|
+
const explicitCdpPort = optionString(options, "cdpPort");
|
|
49
|
+
const explicitWatcherPort = optionString(options, "watcherPort") ?? optionString(options, "metroPort");
|
|
42
50
|
if (explicitCdpPort) {
|
|
43
51
|
process.env.CDP_PORT = explicitCdpPort;
|
|
44
52
|
process.env.RECIPE_CDP_PORT = explicitCdpPort;
|
|
45
53
|
}
|
|
46
54
|
if (explicitWatcherPort) process.env.WATCHER_PORT = explicitWatcherPort;
|
|
47
55
|
try {
|
|
48
|
-
const { ensureExtensionProofRuntime } = await import("../../commands/run-engine.js");
|
|
49
56
|
return await ensureExtensionProofRuntime(target, heal, state, json, { onRecovery });
|
|
50
57
|
} finally {
|
|
51
58
|
restoreEnv("CDP_PORT", previousCdpPort);
|
|
@@ -54,12 +61,120 @@ const extensionRun = {
|
|
|
54
61
|
}
|
|
55
62
|
};
|
|
56
63
|
},
|
|
57
|
-
launchedBrowser: (target, artifactsDir, cdpPort) => launchedBrowser(target, artifactsDir, cdpPort)
|
|
64
|
+
launchedBrowser: (target, artifactsDir, cdpPort) => launchedBrowser(target, artifactsDir, cdpPort),
|
|
65
|
+
browserProvenance: (browser) => ({
|
|
66
|
+
browser: browser.browser,
|
|
67
|
+
browser_version: browser.version,
|
|
68
|
+
browser_source: browser.source,
|
|
69
|
+
extension_loading: browser.extensionLoading
|
|
70
|
+
})
|
|
58
71
|
};
|
|
72
|
+
async function ensureExtensionProofRuntime(target, heal, state, json, deps = {}) {
|
|
73
|
+
const decide = deps.decide ?? (async () => {
|
|
74
|
+
const { decideExtensionReadiness } = await import("./runtime-decision.js");
|
|
75
|
+
const port = Number(process.env.CDP_PORT);
|
|
76
|
+
return decideExtensionReadiness(target, {
|
|
77
|
+
...Number.isInteger(port) && port > 0 ? { cdpPort: port } : {},
|
|
78
|
+
pageMode: "home-or-sidepanel"
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
const initial = await decide();
|
|
82
|
+
if (initial.decision === "ready") return null;
|
|
83
|
+
if (initial.reasonCode === "release-artifact-identity-invalid" || initial.reasonCode === "release-artifact-runtime-missing" || initial.reasonCode === "release-artifact-runtime-stale") {
|
|
84
|
+
const message = initial.reasons[0] ?? "The loaded release artifact identity is invalid.";
|
|
85
|
+
const userAction2 = "rerun runtime-launch with the same artifact source";
|
|
86
|
+
emitProofFailure(json, {
|
|
87
|
+
recoverable: false,
|
|
88
|
+
error: { code: "RELEASE_ARTIFACT_NOT_CURRENT", message, userAction: userAction2 }
|
|
89
|
+
});
|
|
90
|
+
return EXIT.infra;
|
|
91
|
+
}
|
|
92
|
+
if (initial.reasonCode === "runtime-dist-check-failed") {
|
|
93
|
+
const message = `Extension proof runtime freshness could not be checked: ${initial.reasons[0] ?? initial.decision}`;
|
|
94
|
+
const userAction2 = `mm-harness doctor --adapter extension --target ${JSON.stringify(path.resolve(target))}`;
|
|
95
|
+
emitProofFailure(json, {
|
|
96
|
+
recoverable: false,
|
|
97
|
+
error: { code: "EXTENSION_RUNTIME_CHECK_FAILED", message, userAction: userAction2 }
|
|
98
|
+
});
|
|
99
|
+
return EXIT.infra;
|
|
100
|
+
}
|
|
101
|
+
if (![
|
|
102
|
+
"dist-stale",
|
|
103
|
+
"dist-missing",
|
|
104
|
+
"runtime-dist-stale",
|
|
105
|
+
"runtime-dist-missing"
|
|
106
|
+
].includes(initial.reasonCode)) {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const tier = initial.decision === "build" ? "build" : "quick";
|
|
110
|
+
const canHeal = heal === "auto" || heal === "infra-only" && tier === "quick";
|
|
111
|
+
const targetArg = JSON.stringify(path.resolve(target));
|
|
112
|
+
const userAction = tier === "build" ? `mm-harness launch --build --verify --adapter extension --target ${targetArg}` : `mm-harness launch --verify --adapter extension --target ${targetArg}`;
|
|
113
|
+
if (!canHeal) {
|
|
114
|
+
const message = `Extension proof runtime is not current (${initial.reasonCode}): ${initial.reasons[0] ?? initial.decision}`;
|
|
115
|
+
emitProofFailure(json, {
|
|
116
|
+
recoverable: true,
|
|
117
|
+
mutations: state.mutations,
|
|
118
|
+
error: { code: "EXTENSION_RUNTIME_NOT_CURRENT", message, userAction }
|
|
119
|
+
});
|
|
120
|
+
return EXIT.infra;
|
|
121
|
+
}
|
|
122
|
+
const recoveryCode = tier === "build" ? "extension.runtime_rebuilt" : "extension.runtime_reloaded";
|
|
123
|
+
const productConfigBlock = tier === "build" ? (await import("./product-config.js")).extensionProductConfigBlock(target) : null;
|
|
124
|
+
if (productConfigBlock) {
|
|
125
|
+
const message = productConfigBlock.message;
|
|
126
|
+
const userAction2 = productConfigBlock.userAction;
|
|
127
|
+
emitProofFailure(json, {
|
|
128
|
+
recoverable: false,
|
|
129
|
+
mutations: state.mutations,
|
|
130
|
+
error: { code: "EXTENSION_PRODUCT_CONFIG_REQUIRED", message, userAction: userAction2 }
|
|
131
|
+
});
|
|
132
|
+
return EXIT.infra;
|
|
133
|
+
}
|
|
134
|
+
state.attemptedRecoveries.push(recoveryCode);
|
|
135
|
+
deps.onRecovery?.(recoveryCode);
|
|
136
|
+
if (!json)
|
|
137
|
+
console.error(
|
|
138
|
+
`\u2192 Extension proof preflight: ${initial.reasonCode}; ${tier === "build" ? "rebuilding" : "reloading"} before execution`
|
|
139
|
+
);
|
|
140
|
+
const launch = deps.launch ?? (async (requestedTier) => {
|
|
141
|
+
const { launchExtension } = await import("../../commands/launch/extension.js");
|
|
142
|
+
const { readExtensionPinnedFlags } = await import("./feature-flags.js");
|
|
143
|
+
const { fixtureFeatureFlags, remoteFlagRequestFor } = await import("../../feature-flags.js");
|
|
144
|
+
const { walletFixturePath } = await import("../../paths.js");
|
|
145
|
+
return launchExtension(
|
|
146
|
+
target,
|
|
147
|
+
requestedTier,
|
|
148
|
+
false,
|
|
149
|
+
"fullscreen",
|
|
150
|
+
remoteFlagRequestFor(readExtensionPinnedFlags(target).pinned ?? fixtureFeatureFlags(walletFixturePath(target)))
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
const result = await launch(tier);
|
|
154
|
+
const verified = result.status === 0 ? await decide() : initial;
|
|
155
|
+
if (result.status !== 0 || verified.decision !== "ready") {
|
|
156
|
+
const message = `Extension runtime recovery did not produce a current healthy runtime (${verified.reasonCode}).`;
|
|
157
|
+
emitProofFailure(json, {
|
|
158
|
+
recoverable: false,
|
|
159
|
+
attemptedRecoveries: state.attemptedRecoveries,
|
|
160
|
+
error: { code: "EXTENSION_RUNTIME_RECOVERY_FAILED", message, userAction, originalError: result.output }
|
|
161
|
+
});
|
|
162
|
+
return EXIT.infra;
|
|
163
|
+
}
|
|
164
|
+
state.recovered.push(recoveryCode);
|
|
165
|
+
state.mutations.push({
|
|
166
|
+
type: "runtime",
|
|
167
|
+
action: tier === "build" ? "rebuilt" : "reloaded",
|
|
168
|
+
reasonCode: initial.reasonCode
|
|
169
|
+
});
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
59
172
|
const extensionRecording = {
|
|
60
173
|
target: (context) => resolveExtensionRecordingTarget(context),
|
|
61
174
|
framed: {
|
|
62
|
-
browserPid: (projectRoot, artifactsDir, cdpPort) => resolveExtensionBrowserPid(projectRoot, artifactsDir, cdpPort)
|
|
175
|
+
browserPid: (projectRoot, artifactsDir, cdpPort) => resolveExtensionBrowserPid(projectRoot, artifactsDir, cdpPort),
|
|
176
|
+
// cdp.mjs snapshots the framed recording of this pid.
|
|
177
|
+
activePidEnv: "METAMASK_RECIPE_EXTENSION_ACTIVE_RECORDING_PID"
|
|
63
178
|
}
|
|
64
179
|
};
|
|
65
180
|
async function resolveExtensionRecordingTarget(context) {
|
|
@@ -80,17 +195,22 @@ const extensionDiagnostics = {
|
|
|
80
195
|
start: (projectRoot) => ensureExtensionConsoleCapture(projectRoot),
|
|
81
196
|
files: (projectRoot) => extensionCaptureFiles(projectRoot),
|
|
82
197
|
cdpPort: () => extensionCdpPort(),
|
|
83
|
-
verifyControl: (capture) => verifyExtensionConsoleControl(capture)
|
|
198
|
+
verifyControl: (capture) => verifyOwnedCollectorControl(capture, () => verifyExtensionConsoleControl(capture))
|
|
84
199
|
}
|
|
85
200
|
};
|
|
86
201
|
const extensionObservation = {
|
|
87
202
|
network: {
|
|
88
|
-
backend: async (_target, env, artifactsDir) => (await import("
|
|
203
|
+
backend: async (_target, env, artifactsDir) => (await import("./network-observer.js")).createExtensionNetworkBackend(env, artifactsDir),
|
|
89
204
|
actions: true
|
|
90
205
|
},
|
|
91
206
|
performance: {
|
|
92
|
-
|
|
93
|
-
|
|
207
|
+
start: async (context) => {
|
|
208
|
+
const observation = await import("../../performance-observation.js");
|
|
209
|
+
return observation.startRunPerformanceObservation({
|
|
210
|
+
backend: (target, env, ports) => observation.createExtensionPerformanceObserver(target, env, ports),
|
|
211
|
+
platform: () => "extension"
|
|
212
|
+
}, context);
|
|
213
|
+
}
|
|
94
214
|
}
|
|
95
215
|
};
|
|
96
216
|
function restoreEnv(key, value) {
|
|
@@ -98,6 +218,7 @@ function restoreEnv(key, value) {
|
|
|
98
218
|
else process.env[key] = value;
|
|
99
219
|
}
|
|
100
220
|
export {
|
|
221
|
+
ensureExtensionProofRuntime,
|
|
101
222
|
extensionDiagnostics,
|
|
102
223
|
extensionObservation,
|
|
103
224
|
extensionRecording,
|
|
@@ -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";
|
|
@@ -7,7 +8,7 @@ import {
|
|
|
7
8
|
depsCheck,
|
|
8
9
|
INSTALL_MARKERS
|
|
9
10
|
} from "@farmslot/recipe-runner/runtime/deps-readiness";
|
|
10
|
-
import {
|
|
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,8 +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
4
|
import { defineAdapter } from "@farmslot/adapter-sdk";
|
|
4
|
-
import {
|
|
5
|
-
import { shellQuote } from "../../commands/parse-args.js";
|
|
5
|
+
import { runnerDir } from "../../paths.js";
|
|
6
6
|
import {
|
|
7
7
|
isExtensionWatcherLive,
|
|
8
8
|
resolveExtensionSlotPorts,
|
|
@@ -15,6 +15,7 @@ import { extensionActions } from "./actions.js";
|
|
|
15
15
|
import { extensionHarness, extensionPrepare, extensionRuntimeContext } from "./overlay.js";
|
|
16
16
|
import { extensionReadiness, extensionRuntimeDecision } from "./readiness.js";
|
|
17
17
|
import { extensionDiagnostics, extensionObservation, extensionRecording, extensionRun } from "./run.js";
|
|
18
|
+
import { checkoutHas, checkoutHasDir } from "../checkout-files.js";
|
|
18
19
|
function watcherStatus(buildLog) {
|
|
19
20
|
if (buildLog === "ok") return "up";
|
|
20
21
|
if (buildLog === "no-watch") return "down";
|
|
@@ -102,6 +103,18 @@ const extensionSurface = defineAdapter({
|
|
|
102
103
|
appLogSource(target) {
|
|
103
104
|
return { label: "extension", path: recipeRuntimePath(target, "extension-console.log") };
|
|
104
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
|
+
},
|
|
105
118
|
hints: {
|
|
106
119
|
launch: "mm-harness launch",
|
|
107
120
|
relaunch: "mm-harness launch --build",
|
|
@@ -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,4 +1,5 @@
|
|
|
1
1
|
import { manifestPath } from "../../paths.js";
|
|
2
|
+
import { perpsOrderInputFindings } from "../perps-order-inputs.js";
|
|
2
3
|
const NATIVE_PROVIDER_UI_ACTIONS = /* @__PURE__ */ new Set([
|
|
3
4
|
"ui.press",
|
|
4
5
|
"ui.key_press",
|
|
@@ -47,7 +48,9 @@ const mobileActions = {
|
|
|
47
48
|
}
|
|
48
49
|
}),
|
|
49
50
|
wrap: async (adapters) => (await import("./runtime-identity.js")).withMobileNativeRuntimeIdentity(adapters),
|
|
50
|
-
lifecycle: async (adapters) => (await import("./lifecycle.js")).mobileSourceAwareLifecycleAdapters(adapters)
|
|
51
|
+
lifecycle: async (adapters) => (await import("./lifecycle.js")).mobileSourceAwareLifecycleAdapters(adapters),
|
|
52
|
+
// ensure_positions and ensure_orders with an open or present state place an order.
|
|
53
|
+
inputFindings: (nodeId, node) => perpsOrderInputFindings(nodeId, node, { ensureChecksOnly: false })
|
|
51
54
|
};
|
|
52
55
|
export {
|
|
53
56
|
mobileActions
|
|
@@ -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" }] : [
|