@deeeed/metamask-harness 0.34.1 → 0.34.2
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 +13 -0
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +222 -0
- package/adapters/mobile/bridge-runtime/console-forwarder.cjs +22 -1
- package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +18 -0
- package/adapters/mobile/open-device.sh +6 -4
- package/dist/adapters/mobile/prepare.js +1 -4
- package/dist/adapters.js +134 -6
- package/dist/commands/launch/mobile.js +16 -2
- package/dist/live-adapter-contract.js +6 -6
- package/dist/recipe-security.js +2 -0
- package/dist/runner.js +53 -8
- package/dist/runtime-context.js +1 -0
- package/library/actions/mobile/perps/measure_homepage_visible.mjs +4 -0
- package/library/actions/mobile/perps/performance-capture.mjs +506 -120
- package/library/actions/mobile/perps/perps.mjs +221 -38
- package/library/actions/mobile/perps/prepare_local_snapshot_endpoint.mjs +58 -0
- package/library/actions/mobile/platform/bridge.mjs +38 -5
- package/library/actions/mobile/wallet/ensure_unlocked.mjs +5 -1
- package/library/manifests/mobile.action-manifest.json +226 -512
- package/library/recipes/mobile/perps/performance.homepage.cold-position-sample.recipe.json +120 -0
- package/library/recipes/mobile/perps/performance.homepage.ios-background-reconnect.recipe.json +7 -6
- package/library/recipes/mobile/perps/performance.homepage.ios-cold-no-cache.recipe.json +5 -5
- package/package.json +1 -1
package/dist/runner.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { execSync } from "node:child_process";
|
|
1
|
+
import { execFileSync, execSync } from "node:child_process";
|
|
2
2
|
import { OFFICIAL_RECIPE_ACTIONS } from "@farmslot/protocol";
|
|
3
3
|
import { createMetaMaskAdapters, createMetaMaskUiTransport } from "./adapters.js";
|
|
4
4
|
import { bridgeCommand } from "../library/actions/mobile/platform/bridge.mjs";
|
|
@@ -239,6 +239,8 @@ function isAutomaticHudProgress(action, node, nodeId) {
|
|
|
239
239
|
function mobileSourceAwareLifecycleAdapters(adapter, lifecycle, readinessProbe = probeMobileLifecycleRuntime, sourceFreshness = {
|
|
240
240
|
fingerprint: mobileSourceFingerprint,
|
|
241
241
|
record: recordMobileSourceBaseline
|
|
242
|
+
}, processIdentity = {
|
|
243
|
+
readIosPid: readIosAppPid
|
|
242
244
|
}) {
|
|
243
245
|
if (adapter !== "mobile") return lifecycle;
|
|
244
246
|
return lifecycle.map((entry) => ({
|
|
@@ -246,6 +248,8 @@ function mobileSourceAwareLifecycleAdapters(adapter, lifecycle, readinessProbe =
|
|
|
246
248
|
async execute(node, context) {
|
|
247
249
|
const command = node.command ?? node.event ?? node.state;
|
|
248
250
|
const reloadsSource = command === "launch" || command === "foreground" || command === "restart";
|
|
251
|
+
const checksIosContinuity = command === "foreground" && !isAndroidLifecycle(node, context.env ?? {});
|
|
252
|
+
const processBefore = checksIosContinuity ? processIdentity.readIosPid(node, context) : void 0;
|
|
249
253
|
const fingerprint = reloadsSource ? sourceFreshness.fingerprint(context.projectRoot) : void 0;
|
|
250
254
|
const androidRestart = command === "restart" && isAndroidLifecycle(node, context.env ?? {});
|
|
251
255
|
const initialNode = androidRestart ? { ...node, settle_ms: 0 } : node;
|
|
@@ -261,6 +265,25 @@ function mobileSourceAwareLifecycleAdapters(adapter, lifecycle, readinessProbe =
|
|
|
261
265
|
if (reloadsSource) {
|
|
262
266
|
await readinessProbe(node, context);
|
|
263
267
|
}
|
|
268
|
+
if (checksIosContinuity) {
|
|
269
|
+
const processAfter = processIdentity.readIosPid(node, context);
|
|
270
|
+
const actualTransition = processBefore !== null && processBefore === processAfter ? "foreground_resume" : processAfter !== null ? "cold_relaunch" : "unknown";
|
|
271
|
+
const resultRecord = asRecord(result);
|
|
272
|
+
result = {
|
|
273
|
+
...resultRecord,
|
|
274
|
+
output: {
|
|
275
|
+
...asRecord(resultRecord.output),
|
|
276
|
+
actualTransition,
|
|
277
|
+
processBefore,
|
|
278
|
+
processAfter
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
if (node.require_process_continuity === true && actualTransition !== "foreground_resume") {
|
|
282
|
+
throw new Error(
|
|
283
|
+
`iOS foreground did not preserve the app process (actualTransition=${actualTransition}, before=${String(processBefore)}, after=${String(processAfter)}); this lifecycle sample is a cold relaunch, not a reconnect.`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
264
287
|
if (fingerprint !== void 0 && !sourceFreshness.record(context.projectRoot, fingerprint)) {
|
|
265
288
|
throw new Error(
|
|
266
289
|
"Mobile source changed while the app was reloading; the loaded-source baseline was not recorded. Next: retry app.lifecycle restart."
|
|
@@ -270,6 +293,26 @@ function mobileSourceAwareLifecycleAdapters(adapter, lifecycle, readinessProbe =
|
|
|
270
293
|
}
|
|
271
294
|
}));
|
|
272
295
|
}
|
|
296
|
+
function readIosAppPid(node, context) {
|
|
297
|
+
const env = context.env ?? {};
|
|
298
|
+
const device = node.simulator ?? node.ios_simulator ?? env.SIM_UDID ?? env.IOS_SIMULATOR ?? process.env.SIM_UDID ?? process.env.IOS_SIMULATOR;
|
|
299
|
+
const bundleId = node.bundle_id ?? node.bundleId ?? env.IOS_BUNDLE_ID ?? process.env.IOS_BUNDLE_ID ?? "io.metamask.MetaMask";
|
|
300
|
+
if (typeof device !== "string" || typeof bundleId !== "string") return null;
|
|
301
|
+
try {
|
|
302
|
+
const output = execFileSync(
|
|
303
|
+
"xcrun",
|
|
304
|
+
["simctl", "spawn", device, "launchctl", "list"],
|
|
305
|
+
{ encoding: "utf8", timeout: 5e3 }
|
|
306
|
+
);
|
|
307
|
+
const labelPrefix = `UIKitApplication:${bundleId}[`;
|
|
308
|
+
const line = output.split("\n").find((candidate) => candidate.includes(labelPrefix));
|
|
309
|
+
if (!line) return null;
|
|
310
|
+
const pid = Number.parseInt(line.trim().split(/\s+/u)[0] ?? "", 10);
|
|
311
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
312
|
+
} catch {
|
|
313
|
+
return null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
273
316
|
function isAndroidLifecycle(node, env) {
|
|
274
317
|
const platform = node.platform ?? env.PLATFORM ?? process.env.PLATFORM;
|
|
275
318
|
if (platform === "android") return true;
|
|
@@ -299,10 +342,9 @@ function mergeAndroidRestartResults(initialResult, foregroundResult) {
|
|
|
299
342
|
}
|
|
300
343
|
async function probeMobileLifecycleRuntime(node, context) {
|
|
301
344
|
const command = node.command ?? node.event ?? node.state;
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
node.runtime_ready_timeout_ms
|
|
305
|
-
defaultTimeoutMs
|
|
345
|
+
const timeoutMs = resolveMobileLifecycleReadinessTimeout(
|
|
346
|
+
command,
|
|
347
|
+
node.runtime_ready_timeout_ms
|
|
306
348
|
);
|
|
307
349
|
const deadline = Date.now() + timeoutMs;
|
|
308
350
|
let lastError;
|
|
@@ -328,8 +370,10 @@ async function probeMobileLifecycleRuntime(node, context) {
|
|
|
328
370
|
`Mobile lifecycle ${String(command)} did not expose a usable pinned __AGENTIC__ runtime within ${timeoutMs}ms: ${lastError instanceof Error ? lastError.message : String(lastError)}`
|
|
329
371
|
);
|
|
330
372
|
}
|
|
331
|
-
function
|
|
332
|
-
if (value === void 0)
|
|
373
|
+
function resolveMobileLifecycleReadinessTimeout(command, value) {
|
|
374
|
+
if (value === void 0) {
|
|
375
|
+
return command === "launch" || command === "restart" || command === "foreground" ? 6e4 : 3e4;
|
|
376
|
+
}
|
|
333
377
|
const timeout = Number(value);
|
|
334
378
|
if (!Number.isInteger(timeout) || timeout < 1e3 || timeout > 12e4) {
|
|
335
379
|
throw new Error(
|
|
@@ -364,5 +408,6 @@ export {
|
|
|
364
408
|
createMetaMaskMobileRunner,
|
|
365
409
|
createMetaMaskRunner,
|
|
366
410
|
isAutomaticHudProgress,
|
|
367
|
-
mobileSourceAwareLifecycleAdapters
|
|
411
|
+
mobileSourceAwareLifecycleAdapters,
|
|
412
|
+
resolveMobileLifecycleReadinessTimeout
|
|
368
413
|
};
|
package/dist/runtime-context.js
CHANGED
|
@@ -244,6 +244,7 @@ function persistExplicitDevicePin(target, device) {
|
|
|
244
244
|
return;
|
|
245
245
|
}
|
|
246
246
|
const next = { ...existing };
|
|
247
|
+
next.platform = device.platform;
|
|
247
248
|
if (device.platform === "ios") {
|
|
248
249
|
const simulatorName = device.name ? device.name.replace(/_/gu, " ").trim() : device.id;
|
|
249
250
|
next.simulator = simulatorName;
|