@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
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { execFile } from "node:child_process";
|
|
2
|
-
import { promisify } from "node:util";
|
|
3
|
-
const execFileAsync = promisify(execFile);
|
|
4
|
-
async function gitLibraryProvenance(root) {
|
|
5
|
-
try {
|
|
6
|
-
const { stdout: tracked } = await execFileAsync("git", ["-C", root, "ls-files", "--", "."], {
|
|
7
|
-
encoding: "utf8",
|
|
8
|
-
timeout: 5e3
|
|
9
|
-
});
|
|
10
|
-
if (!tracked.trim()) return {};
|
|
11
|
-
const [{ stdout: revision }, { stdout: status }] = await Promise.all([
|
|
12
|
-
execFileAsync("git", ["-C", root, "rev-parse", "HEAD"], {
|
|
13
|
-
encoding: "utf8",
|
|
14
|
-
timeout: 5e3
|
|
15
|
-
}),
|
|
16
|
-
execFileAsync(
|
|
17
|
-
"git",
|
|
18
|
-
["-C", root, "status", "--porcelain=v1", "--untracked-files=normal", "--", "."],
|
|
19
|
-
{
|
|
20
|
-
encoding: "utf8",
|
|
21
|
-
timeout: 5e3
|
|
22
|
-
}
|
|
23
|
-
)
|
|
24
|
-
]);
|
|
25
|
-
const trimmedRevision = revision.trim();
|
|
26
|
-
return trimmedRevision ? { revision: trimmedRevision, dirty: status.trim().length > 0 } : {};
|
|
27
|
-
} catch {
|
|
28
|
-
return {};
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
export {
|
|
32
|
-
gitLibraryProvenance
|
|
33
|
-
};
|
|
@@ -1,380 +0,0 @@
|
|
|
1
|
-
import { recordCommandOutput } from "./command-journal.js";
|
|
2
|
-
import { trackCheckoutChild } from "./checkout-lock.js";
|
|
3
|
-
import { createHash } from "node:crypto";
|
|
4
|
-
import { access, mkdtemp, readFile, realpath, rm, writeFile } from "node:fs/promises";
|
|
5
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
-
import os from "node:os";
|
|
7
|
-
import path from "node:path";
|
|
8
|
-
import { spawn } from "node:child_process";
|
|
9
|
-
import { pathToFileURL } from "node:url";
|
|
10
|
-
import { build } from "esbuild";
|
|
11
|
-
import { init, parse } from "es-module-lexer";
|
|
12
|
-
import { resolveRequiredLocalProtocolRoot, runnerDir } from "./paths.js";
|
|
13
|
-
import { adapterRegistry } from "./adapters/registry.js";
|
|
14
|
-
import { getAdapterSurface } from "./adapters/surface.js";
|
|
15
|
-
import { serializeTrustedMutationContext } from "./funding-execution-context.js";
|
|
16
|
-
function actionFileStem(action) {
|
|
17
|
-
return String(action).replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
18
|
-
}
|
|
19
|
-
function actionParts(action) {
|
|
20
|
-
const parts = String(action).split(".").filter(Boolean);
|
|
21
|
-
if (parts.length >= 3 && parts[0] === "metamask") {
|
|
22
|
-
return { family: parts[1], localName: parts.slice(2).join(".") };
|
|
23
|
-
}
|
|
24
|
-
if (parts.length >= 2) {
|
|
25
|
-
return { family: parts[0], localName: parts.slice(1).join(".") };
|
|
26
|
-
}
|
|
27
|
-
return { family: "actions", localName: String(action) };
|
|
28
|
-
}
|
|
29
|
-
function candidateStems(action) {
|
|
30
|
-
const stem = actionFileStem(action);
|
|
31
|
-
const { localName } = actionParts(action);
|
|
32
|
-
const localStem = actionFileStem(localName);
|
|
33
|
-
const stems = [stem];
|
|
34
|
-
if (localStem && localStem !== stem) stems.push(localStem);
|
|
35
|
-
return stems;
|
|
36
|
-
}
|
|
37
|
-
function candidateFamilies(action) {
|
|
38
|
-
const { family } = actionParts(action);
|
|
39
|
-
const families = [family];
|
|
40
|
-
return [...new Set(families)];
|
|
41
|
-
}
|
|
42
|
-
function candidatePaths(platform, action, runtimeEnv = process.env) {
|
|
43
|
-
const stems = candidateStems(action);
|
|
44
|
-
const families = candidateFamilies(action);
|
|
45
|
-
const declaredRoot = declaredActionRoot(
|
|
46
|
-
runtimeEnv.METAMASK_RECIPE_ACTION_SOURCE_MAP ?? process.env.METAMASK_RECIPE_ACTION_SOURCE_MAP,
|
|
47
|
-
action
|
|
48
|
-
);
|
|
49
|
-
const roots = [...new Set((declaredRoot ? [declaredRoot] : [
|
|
50
|
-
runtimeEnv.METAMASK_RECIPE_LIVE_ADAPTER_DIR ?? process.env.METAMASK_RECIPE_LIVE_ADAPTER_DIR,
|
|
51
|
-
path.join(runnerDir, "library/actions")
|
|
52
|
-
]).filter((entry) => Boolean(entry)))];
|
|
53
|
-
const files = [];
|
|
54
|
-
for (const root of roots) {
|
|
55
|
-
for (const family of families) {
|
|
56
|
-
for (const candidateStem of stems) {
|
|
57
|
-
pushCandidateFiles(files, root, platform, family, candidateStem);
|
|
58
|
-
}
|
|
59
|
-
pushDomainDispatcherFiles(files, root, platform, family);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
return files;
|
|
63
|
-
}
|
|
64
|
-
function declaredActionRoot(raw, action) {
|
|
65
|
-
if (!raw) return void 0;
|
|
66
|
-
try {
|
|
67
|
-
const parsed = JSON.parse(raw);
|
|
68
|
-
const root = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed[action] : void 0;
|
|
69
|
-
return typeof root === "string" && root.length > 0 ? root : void 0;
|
|
70
|
-
} catch {
|
|
71
|
-
return void 0;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
function pushCandidateFiles(files, root, platform, family, stem) {
|
|
75
|
-
files.push(path.join(root, platform, family, `${stem}.mjs`));
|
|
76
|
-
files.push(path.join(root, "shared", family, `${stem}.mjs`));
|
|
77
|
-
}
|
|
78
|
-
function pushDomainDispatcherFiles(files, root, platform, family) {
|
|
79
|
-
files.push(path.join(root, platform, family, `${family}.mjs`));
|
|
80
|
-
files.push(path.join(root, "shared", family, `${family}.mjs`));
|
|
81
|
-
}
|
|
82
|
-
async function firstExecutablePath(paths) {
|
|
83
|
-
for (const file of paths) {
|
|
84
|
-
try {
|
|
85
|
-
await access(file);
|
|
86
|
-
return file;
|
|
87
|
-
} catch (error) {
|
|
88
|
-
if (error.code !== "ENOENT") throw error;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
function runProcess(command, args, options) {
|
|
94
|
-
return new Promise((resolve, reject) => {
|
|
95
|
-
let settled = false;
|
|
96
|
-
const child = spawn(command, args, {
|
|
97
|
-
cwd: options.cwd,
|
|
98
|
-
env: options.env,
|
|
99
|
-
stdio: [options.stdin == null ? "ignore" : "pipe", "pipe", "pipe"]
|
|
100
|
-
});
|
|
101
|
-
if (child.pid) trackCheckoutChild(options.cwd, child.pid);
|
|
102
|
-
if (options.stdin != null) {
|
|
103
|
-
child.stdin.on("error", (error) => {
|
|
104
|
-
if (error.code === "EPIPE" || settled) return;
|
|
105
|
-
settled = true;
|
|
106
|
-
reject(error);
|
|
107
|
-
});
|
|
108
|
-
child.stdin.end(options.stdin);
|
|
109
|
-
}
|
|
110
|
-
let stdout = "";
|
|
111
|
-
let stderr = "";
|
|
112
|
-
child.stdout.on("data", (chunk) => {
|
|
113
|
-
stdout += chunk;
|
|
114
|
-
recordCommandOutput(chunk);
|
|
115
|
-
});
|
|
116
|
-
child.stderr.on("data", (chunk) => {
|
|
117
|
-
stderr += chunk;
|
|
118
|
-
recordCommandOutput(chunk);
|
|
119
|
-
});
|
|
120
|
-
const timeout = options.timeoutMs ? setTimeout(() => {
|
|
121
|
-
if (settled) return;
|
|
122
|
-
settled = true;
|
|
123
|
-
child.kill("SIGTERM");
|
|
124
|
-
const killTimer = setTimeout(() => child.kill("SIGKILL"), 1e3);
|
|
125
|
-
child.once("close", () => clearTimeout(killTimer));
|
|
126
|
-
resolve({ exitCode: null, stdout, stderr, timedOut: true });
|
|
127
|
-
}, options.timeoutMs) : void 0;
|
|
128
|
-
child.on("error", (error) => {
|
|
129
|
-
if (settled) return;
|
|
130
|
-
settled = true;
|
|
131
|
-
if (timeout) clearTimeout(timeout);
|
|
132
|
-
reject(error);
|
|
133
|
-
});
|
|
134
|
-
child.on("close", (exitCode) => {
|
|
135
|
-
if (settled) return;
|
|
136
|
-
settled = true;
|
|
137
|
-
if (timeout) clearTimeout(timeout);
|
|
138
|
-
resolve({ exitCode, stdout, stderr, timedOut: false });
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
async function prepareLiveAdapterScript({
|
|
143
|
-
platform,
|
|
144
|
-
action,
|
|
145
|
-
implementationRoot,
|
|
146
|
-
allowRuntimeImports = false
|
|
147
|
-
}) {
|
|
148
|
-
const entryPath = await firstExecutablePath(
|
|
149
|
-
candidatePaths(platform, action, {
|
|
150
|
-
METAMASK_RECIPE_ACTION_SOURCE_MAP: JSON.stringify({ [action]: implementationRoot })
|
|
151
|
-
})
|
|
152
|
-
);
|
|
153
|
-
if (!entryPath) return null;
|
|
154
|
-
const rootReal = await realpath(implementationRoot);
|
|
155
|
-
const entryReal = await realpath(entryPath);
|
|
156
|
-
if (!isPathWithin(rootReal, entryReal)) {
|
|
157
|
-
throw new Error(`Live adapter ${entryPath} resolves outside ${implementationRoot}.`);
|
|
158
|
-
}
|
|
159
|
-
const result = await build({
|
|
160
|
-
entryPoints: [entryReal],
|
|
161
|
-
bundle: true,
|
|
162
|
-
write: false,
|
|
163
|
-
platform: "node",
|
|
164
|
-
format: "esm",
|
|
165
|
-
target: `node${process.versions.node.split(".")[0]}`,
|
|
166
|
-
legalComments: "none",
|
|
167
|
-
sourcemap: false,
|
|
168
|
-
banner: {
|
|
169
|
-
js: `import { createRequire as __mmCreateRequire } from 'node:module';const require = __mmCreateRequire(import.meta.url);process.argv[1] = ${JSON.stringify(entryReal)};`
|
|
170
|
-
},
|
|
171
|
-
plugins: [bindImportMetaUrls()],
|
|
172
|
-
logLevel: "silent"
|
|
173
|
-
});
|
|
174
|
-
const output = result.outputFiles[0];
|
|
175
|
-
if (!output) throw new Error(`Bundling live adapter ${entryReal} produced no executable output.`);
|
|
176
|
-
const sourceText = output.text;
|
|
177
|
-
await init;
|
|
178
|
-
const [imports] = parse(sourceText);
|
|
179
|
-
if (!allowRuntimeImports && imports.some((entry) => entry.d >= 0)) {
|
|
180
|
-
const error = new Error(
|
|
181
|
-
`Live adapter ${entryReal} contains a runtime dynamic import that cannot be bound to the approved bundle. Replace it with a static import so its implementation bytes are included in the plan digest.`
|
|
182
|
-
);
|
|
183
|
-
Object.assign(error, {
|
|
184
|
-
code: "RECIPE_TRUST_UNBOUND_IMPORT",
|
|
185
|
-
userAction: "replace the computed import with a static import, or promote the adapter into an explicitly trusted engineer-owned library"
|
|
186
|
-
});
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
action,
|
|
191
|
-
platform,
|
|
192
|
-
entryPath: entryReal,
|
|
193
|
-
sourceText,
|
|
194
|
-
sourceDigest: `sha256:${createHash("sha256").update(sourceText).digest("hex")}`
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
function bindImportMetaUrls() {
|
|
198
|
-
return {
|
|
199
|
-
name: "bind-import-meta-urls",
|
|
200
|
-
setup(buildContext) {
|
|
201
|
-
buildContext.onLoad({ filter: /\.[cm]?[jt]sx?$/ }, async (args) => {
|
|
202
|
-
const contents = await readFile(args.path, "utf8");
|
|
203
|
-
if (!contents.includes("import.meta.url")) return void 0;
|
|
204
|
-
const extension = path.extname(args.path);
|
|
205
|
-
const loader = extension === ".ts" || extension === ".mts" || extension === ".cts" ? "ts" : extension === ".tsx" ? "tsx" : extension === ".jsx" ? "jsx" : "js";
|
|
206
|
-
return {
|
|
207
|
-
contents: contents.replaceAll(
|
|
208
|
-
"import.meta.url",
|
|
209
|
-
JSON.stringify(pathToFileURL(args.path).href)
|
|
210
|
-
),
|
|
211
|
-
loader
|
|
212
|
-
};
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
function tsxLiveScripts(platform) {
|
|
218
|
-
return platform && adapterRegistry.has(platform) ? getAdapterSurface(platform).actions.tsxLiveScripts : void 0;
|
|
219
|
-
}
|
|
220
|
-
function commandFor(file, projectRoot, platform) {
|
|
221
|
-
const needsTsx = Boolean(tsxLiveScripts(platform)) || importsSourceTypescript(file);
|
|
222
|
-
if (!needsTsx) {
|
|
223
|
-
return { command: process.execPath, args: [file] };
|
|
224
|
-
}
|
|
225
|
-
const tsxBin = resolveTsxBin(projectRoot);
|
|
226
|
-
if (!tsxBin) {
|
|
227
|
-
const where = projectRoot ?? "the checkout";
|
|
228
|
-
const error = new Error(
|
|
229
|
-
`this action runs TypeScript from the checkout but no tsx runtime was found.
|
|
230
|
-
Next: run 'yarn install' in ${where} (tsx is a dev dependency of the checkout); if package imports still fail, run 'yarn build' there`
|
|
231
|
-
);
|
|
232
|
-
error.exitCode = 2;
|
|
233
|
-
throw error;
|
|
234
|
-
}
|
|
235
|
-
return { command: tsxBin, args: [file] };
|
|
236
|
-
}
|
|
237
|
-
function resolveTsxBin(projectRoot) {
|
|
238
|
-
if (process.env.TSX_BIN) return process.env.TSX_BIN;
|
|
239
|
-
const candidates = [];
|
|
240
|
-
if (projectRoot) candidates.push(path.join(projectRoot, "node_modules/.bin/tsx"));
|
|
241
|
-
candidates.push(path.join(runnerDir, "node_modules/.bin/tsx"));
|
|
242
|
-
for (const candidate of candidates) {
|
|
243
|
-
if (existsSync(candidate)) return candidate;
|
|
244
|
-
}
|
|
245
|
-
try {
|
|
246
|
-
const protocolTsx = path.join(resolveRequiredLocalProtocolRoot("TypeScript live adapter execution"), "node_modules/.bin/tsx");
|
|
247
|
-
if (existsSync(protocolTsx)) return protocolTsx;
|
|
248
|
-
} catch {
|
|
249
|
-
}
|
|
250
|
-
return null;
|
|
251
|
-
}
|
|
252
|
-
function importsSourceTypescript(file) {
|
|
253
|
-
return importsSourceTypescriptFrom(file, /* @__PURE__ */ new Set());
|
|
254
|
-
}
|
|
255
|
-
function importsSourceTypescriptFrom(file, visited) {
|
|
256
|
-
const absolute = path.resolve(file);
|
|
257
|
-
if (visited.has(absolute)) return false;
|
|
258
|
-
visited.add(absolute);
|
|
259
|
-
const source = readFileSync(file, "utf8");
|
|
260
|
-
const importPattern = /(?:from\s+|import\(\s*)['"]([^'"]+)['"]/gu;
|
|
261
|
-
for (const match of source.matchAll(importPattern)) {
|
|
262
|
-
const specifier = match[1] ?? "";
|
|
263
|
-
if (specifier.endsWith(".ts")) return true;
|
|
264
|
-
if (!specifier.startsWith(".")) continue;
|
|
265
|
-
if (!specifier.endsWith(".mjs")) continue;
|
|
266
|
-
if (importsSourceTypescriptFrom(path.resolve(path.dirname(absolute), specifier), visited)) {
|
|
267
|
-
return true;
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return false;
|
|
271
|
-
}
|
|
272
|
-
async function resolveLiveAdapter(platform, action, runtimeEnv) {
|
|
273
|
-
return firstExecutablePath(candidatePaths(platform, action, runtimeEnv));
|
|
274
|
-
}
|
|
275
|
-
async function runLiveAdapterScript({ platform, action, node, context, prepared }) {
|
|
276
|
-
const script = prepared?.entryPath ?? await resolveLiveAdapter(platform, action, context?.env);
|
|
277
|
-
if (!script) return null;
|
|
278
|
-
const tempDir = await mkdtemp(path.join(os.tmpdir(), "mm-harness-live-adapter-"));
|
|
279
|
-
const inputPath = path.join(tempDir, "input.json");
|
|
280
|
-
const outputPath = path.join(tempDir, "output.json");
|
|
281
|
-
const input = {
|
|
282
|
-
schemaVersion: 1,
|
|
283
|
-
platform,
|
|
284
|
-
action,
|
|
285
|
-
node,
|
|
286
|
-
context: {
|
|
287
|
-
nodeId: context.nodeId,
|
|
288
|
-
projectRoot: context.projectRoot,
|
|
289
|
-
artifactsDir: context.artifactsDir,
|
|
290
|
-
...context.trustedMutation ? { trustedMutation: serializeTrustedMutationContext(context.trustedMutation) } : {}
|
|
291
|
-
},
|
|
292
|
-
outputPath
|
|
293
|
-
};
|
|
294
|
-
await writeFile(inputPath, `${JSON.stringify(input, null, 2)}
|
|
295
|
-
`);
|
|
296
|
-
const command = prepared ? commandForPrepared(context.projectRoot, platform) : commandFor(script, context.projectRoot, platform);
|
|
297
|
-
const platformEnv = await tsxLiveScripts(platform)?.env(context.projectRoot, tempDir) ?? {};
|
|
298
|
-
const processTimeoutMs = liveAdapterProcessTimeoutMs(node);
|
|
299
|
-
const result = await runProcess(command.command, [...command.args, inputPath], {
|
|
300
|
-
cwd: context.projectRoot,
|
|
301
|
-
env: {
|
|
302
|
-
...process.env,
|
|
303
|
-
...context.env,
|
|
304
|
-
...platformEnv,
|
|
305
|
-
METAMASK_RECIPE_ADAPTER_INPUT: inputPath,
|
|
306
|
-
METAMASK_RECIPE_ADAPTER_OUTPUT: outputPath
|
|
307
|
-
},
|
|
308
|
-
timeoutMs: processTimeoutMs,
|
|
309
|
-
...prepared ? { stdin: prepared.sourceText } : {}
|
|
310
|
-
});
|
|
311
|
-
try {
|
|
312
|
-
if (result.timedOut) {
|
|
313
|
-
throw new Error(`Live adapter ${script} timed out after ${processTimeoutMs}ms.`);
|
|
314
|
-
}
|
|
315
|
-
if (result.exitCode !== 0) {
|
|
316
|
-
const failureOutput = await readFile(outputPath, "utf8").then(JSON.parse).catch(() => null);
|
|
317
|
-
if (Array.isArray(failureOutput?.artifacts)) {
|
|
318
|
-
for (const artifact of failureOutput.artifacts) context.registerArtifact(artifact);
|
|
319
|
-
}
|
|
320
|
-
throw new Error(`Live adapter ${script} exited ${result.exitCode}: ${result.stderr || result.stdout}`);
|
|
321
|
-
}
|
|
322
|
-
let parsed = null;
|
|
323
|
-
try {
|
|
324
|
-
parsed = JSON.parse(await readFile(outputPath, "utf8"));
|
|
325
|
-
} catch (_error) {
|
|
326
|
-
const stdout = result.stdout.trim();
|
|
327
|
-
if (!stdout) throw new Error(`Live adapter ${script} did not write JSON output.`);
|
|
328
|
-
parsed = JSON.parse(stdout);
|
|
329
|
-
}
|
|
330
|
-
return { script, result: parsed };
|
|
331
|
-
} finally {
|
|
332
|
-
await rm(tempDir, { recursive: true, force: true });
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
function liveAdapterProcessTimeoutMs(node) {
|
|
336
|
-
if (node.live_adapter_timeout_ms != null) {
|
|
337
|
-
const timeoutMs = Number(node.live_adapter_timeout_ms);
|
|
338
|
-
return Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 6e4;
|
|
339
|
-
}
|
|
340
|
-
const settleMs = Number(node.settle_ms);
|
|
341
|
-
const settleAllowance = Number.isFinite(settleMs) && settleMs > 0 ? settleMs : 0;
|
|
342
|
-
const actionTimeouts = [
|
|
343
|
-
node.target_timeout_ms,
|
|
344
|
-
node.unlock_timeout_ms,
|
|
345
|
-
node.timeout_ms,
|
|
346
|
-
node.wait_timeout_ms
|
|
347
|
-
].map(Number).filter((value) => Number.isFinite(value) && value > 0);
|
|
348
|
-
if (actionTimeouts.length > 0) {
|
|
349
|
-
return Math.max(
|
|
350
|
-
6e4,
|
|
351
|
-
actionTimeouts.reduce((total, value) => total + value, 0) + settleAllowance + 5e3
|
|
352
|
-
);
|
|
353
|
-
}
|
|
354
|
-
return 6e4 + settleAllowance;
|
|
355
|
-
}
|
|
356
|
-
function commandForPrepared(projectRoot, platform) {
|
|
357
|
-
if (!tsxLiveScripts(platform)) {
|
|
358
|
-
return { command: process.execPath, args: ["--input-type=module", "-"] };
|
|
359
|
-
}
|
|
360
|
-
const tsxBin = resolveTsxBin(projectRoot);
|
|
361
|
-
if (!tsxBin) {
|
|
362
|
-
const error = new Error(
|
|
363
|
-
`this action imports TypeScript from the checkout but no tsx runtime was found.
|
|
364
|
-
Next: run 'yarn install' in ${projectRoot}`
|
|
365
|
-
);
|
|
366
|
-
error.exitCode = 2;
|
|
367
|
-
throw error;
|
|
368
|
-
}
|
|
369
|
-
return { command: tsxBin, args: ["--input-type=module", "-"] };
|
|
370
|
-
}
|
|
371
|
-
function isPathWithin(root, candidate) {
|
|
372
|
-
const relative = path.relative(root, candidate);
|
|
373
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
374
|
-
}
|
|
375
|
-
export {
|
|
376
|
-
liveAdapterProcessTimeoutMs,
|
|
377
|
-
prepareLiveAdapterScript,
|
|
378
|
-
resolveLiveAdapter,
|
|
379
|
-
runLiveAdapterScript
|
|
380
|
-
};
|
package/dist/recording-target.js
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { spawnSync } from "node:child_process";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
const ANDROID_RECORDING_TARGET_PREFIX = "android-device:";
|
|
5
|
-
const IOS_SIMULATOR_RECORDING_TARGET_PREFIX = "ios-simulator:";
|
|
6
|
-
function createMetaMaskRecordingTargetProvider(adapter) {
|
|
7
|
-
return {
|
|
8
|
-
async resolveRecordingTarget(context) {
|
|
9
|
-
const { getAdapterSurface } = await import("./adapters/surface.js");
|
|
10
|
-
const recording = getAdapterSurface(adapter).recording;
|
|
11
|
-
if (!recording) throw new Error(`--record-video is not implemented for the ${adapter} adapter.`);
|
|
12
|
-
return recording.target(context);
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
function resolveAndroidDeviceSerial(env = process.env) {
|
|
17
|
-
return env.ADB_SERIAL?.trim() || process.env.ADB_SERIAL?.trim() || void 0;
|
|
18
|
-
}
|
|
19
|
-
function captureHelperSupportsRecordSessionSnapshots(projectRoot) {
|
|
20
|
-
return captureHelperSupportsCapability(projectRoot, "record_session_snapshot");
|
|
21
|
-
}
|
|
22
|
-
function captureHelperSupportsCapability(projectRoot, capability) {
|
|
23
|
-
const result = spawnSync(captureHelperPath(), ["version", "--json"], {
|
|
24
|
-
cwd: projectRoot,
|
|
25
|
-
encoding: "utf8"
|
|
26
|
-
});
|
|
27
|
-
if (result.status !== 0) return false;
|
|
28
|
-
try {
|
|
29
|
-
const parsed = JSON.parse(result.stdout);
|
|
30
|
-
return Array.isArray(parsed.capabilities) && parsed.capabilities.includes(capability);
|
|
31
|
-
} catch {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
function resolveMobileIosSimulatorName(env = process.env) {
|
|
36
|
-
const explicit = env.IOS_SIMULATOR?.trim() || env.SIM_UDID?.trim();
|
|
37
|
-
if (explicit) return explicit;
|
|
38
|
-
const slot = env.FARMSLOT_SLOT_ID?.trim() || env.SLOT_ID?.trim();
|
|
39
|
-
if (!slot) return void 0;
|
|
40
|
-
const suffix = slot.includes("-") ? slot.slice(slot.lastIndexOf("-") + 1) : slot;
|
|
41
|
-
return suffix || void 0;
|
|
42
|
-
}
|
|
43
|
-
function resolveMobileIosSimulatorPid(simulator) {
|
|
44
|
-
const result = spawnSync(
|
|
45
|
-
captureHelperPath(),
|
|
46
|
-
["resolve", "--app-name", "Simulator", "--window-name", simulator, "--json"],
|
|
47
|
-
{ encoding: "utf8" }
|
|
48
|
-
);
|
|
49
|
-
if (result.status !== 0) return null;
|
|
50
|
-
try {
|
|
51
|
-
const parsed = JSON.parse(result.stdout);
|
|
52
|
-
return parsePositivePid(parsed.selected?.pid);
|
|
53
|
-
} catch {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
function resolveExtensionBrowserPid(projectRoot, artifactsDir, cdpPort) {
|
|
58
|
-
const explicit = parsePositivePid(process.env.METAMASK_RECIPE_EXTENSION_BROWSER_PID);
|
|
59
|
-
if (explicit) return explicit;
|
|
60
|
-
if (cdpPort) {
|
|
61
|
-
const lsof = spawnSync("lsof", ["-nP", `-iTCP:${cdpPort}`, "-sTCP:LISTEN", "-t"], {
|
|
62
|
-
cwd: projectRoot,
|
|
63
|
-
encoding: "utf8"
|
|
64
|
-
});
|
|
65
|
-
if (lsof.status === 0) {
|
|
66
|
-
const pid = parsePositivePid(String(lsof.stdout).split(/\s+/u).find(Boolean));
|
|
67
|
-
if (pid) return pid;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
for (const file of [
|
|
71
|
-
path.join(artifactsDir, "extension-runtime/runtime.json"),
|
|
72
|
-
path.join(projectRoot, "temp/recipe/runtime/runtime.json")
|
|
73
|
-
]) {
|
|
74
|
-
const pid = parsePositivePid(readJsonFile(file)?.pid);
|
|
75
|
-
if (pid) return pid;
|
|
76
|
-
}
|
|
77
|
-
for (const file of [
|
|
78
|
-
path.join(projectRoot, "temp/recipe/runtime/chromium.pid"),
|
|
79
|
-
path.join(projectRoot, "temp/recipe/runtime/browser.pid")
|
|
80
|
-
]) {
|
|
81
|
-
const pid = parsePositivePid(readTextFile(file));
|
|
82
|
-
if (pid) return pid;
|
|
83
|
-
}
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
function captureHelperPath() {
|
|
87
|
-
return process.env.CAPTURE_HELPER_PATH || "capture-helper";
|
|
88
|
-
}
|
|
89
|
-
function parsePositivePid(value) {
|
|
90
|
-
const pid = Number(String(value ?? "").trim());
|
|
91
|
-
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
92
|
-
}
|
|
93
|
-
function readJsonFile(file) {
|
|
94
|
-
if (!fs.existsSync(file)) return null;
|
|
95
|
-
try {
|
|
96
|
-
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
97
|
-
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
98
|
-
} catch {
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
function readTextFile(file) {
|
|
103
|
-
if (!fs.existsSync(file)) return "";
|
|
104
|
-
try {
|
|
105
|
-
return fs.readFileSync(file, "utf8");
|
|
106
|
-
} catch {
|
|
107
|
-
return "";
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
export {
|
|
111
|
-
ANDROID_RECORDING_TARGET_PREFIX,
|
|
112
|
-
IOS_SIMULATOR_RECORDING_TARGET_PREFIX,
|
|
113
|
-
captureHelperSupportsCapability,
|
|
114
|
-
captureHelperSupportsRecordSessionSnapshots,
|
|
115
|
-
createMetaMaskRecordingTargetProvider,
|
|
116
|
-
resolveAndroidDeviceSerial,
|
|
117
|
-
resolveExtensionBrowserPid,
|
|
118
|
-
resolveMobileIosSimulatorName,
|
|
119
|
-
resolveMobileIosSimulatorPid
|
|
120
|
-
};
|