@deeeed/metamask-harness 0.79.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 +47 -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/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/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 +2 -2
- package/dist/adapters/core/surface.js +16 -1
- 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 +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/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 +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 +8 -7
- 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/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 +7 -1
- 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 +2 -8
- 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 +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/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/doctor.js +2 -3
- 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 +34 -64
- package/dist/performance-observation.js +2 -2
- package/dist/progress.js +1 -1
- package/dist/recipe-assistance-context.js +1 -3
- package/dist/recipe-security.js +2 -59
- package/dist/review/knowledge.js +2 -2
- package/dist/runner.js +5 -3
- package/dist/runtime-context.js +1 -1
- package/dist/task-view.js +2 -3
- package/docs/CONTRIBUTING.md +1 -1
- 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 -9
- package/adapters/extension/lib/slot-title.cjs +0 -292
- package/adapters/mobile/bridge-runtime/console-forwarder.cjs +0 -472
- package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +0 -125
- package/adapters/mobile/bridge-runtime/lib/cdp-broker.cjs +0 -1055
- package/adapters/mobile/bridge-runtime/lib/cdp-eval.cjs +0 -110
- package/adapters/mobile/bridge-runtime/lib/config.cjs +0 -61
- package/adapters/mobile/bridge-runtime/lib/console-format.cjs +0 -53
- package/adapters/mobile/bridge-runtime/lib/devtools-proxy.cjs +0 -177
- package/adapters/mobile/bridge-runtime/lib/issue-capture.cjs +0 -446
- package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +0 -84
- package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +0 -403
- package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +0 -116
- package/adapters/mobile/coalesce-metro-log.cjs +0 -24
- package/adapters/mobile/launch-metro.cjs +0 -77
- package/adapters/mobile/metro-config.cjs +0 -98
- package/adapters/mobile/metro-log-generation.cjs +0 -106
- package/dist/adapters/mobile/frame-metrics.js +0 -118
- package/dist/adapters/mobile/video-recorder.js +0 -289
- package/dist/artifact-files.js +0 -92
- package/dist/checkout-lock.js +0 -149
- package/dist/cli-color.js +0 -98
- package/dist/command-journal.js +0 -308
- package/dist/commands/last.js +0 -60
- package/dist/commands/launch/index.js +0 -109
- package/dist/commands/parse-args.js +0 -279
- package/dist/commands/reload.js +0 -41
- package/dist/commands/run-report.js +0 -241
- package/dist/commands/shared.js +0 -323
- package/dist/commands/stop.js +0 -60
- package/dist/devices.js +0 -100
- package/dist/execution-provenance.js +0 -332
- package/dist/harness.js +0 -451
- package/dist/heal-bounds.js +0 -137
- package/dist/json-stream.js +0 -60
- package/dist/leaf-invoke.js +0 -19
- package/dist/library-provenance.js +0 -33
- package/dist/live-adapter-contract.js +0 -380
- package/dist/recording-target.js +0 -120
- package/dist/run-diagnostics.js +0 -364
- package/dist/run-recording.js +0 -481
- package/dist/runtime-proof.js +0 -90
- package/library/actions/mobile/platform/tool-paths.mjs +0 -123
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// MetaMask Mobile recovery lines for the bridge error codes that
|
|
4
|
+
// @farmslot/adapter-rn classifies; cdp-bridge.cjs prints one after a coded failure.
|
|
5
|
+
//
|
|
6
|
+
// Every coded failure teaches the escape for the caller's ACTUAL situation — a
|
|
7
|
+
// down/transitioning target is recoverable, so the Next: line names the action
|
|
8
|
+
// that brings it back rather than leaving the operator to guess.
|
|
9
|
+
const TEACHING_BY_ERROR_CODE = {
|
|
10
|
+
NO_TARGET:
|
|
11
|
+
'Next: bring the app to the foreground with `mm-harness launch <platform>` so a debug target is available.',
|
|
12
|
+
CDP_TIMEOUT:
|
|
13
|
+
'Next: the app is reloading or busy — retry, or `mm-harness launch <platform>` to foreground it.',
|
|
14
|
+
WS_CLOSED:
|
|
15
|
+
'Next: the Hermes debug page closed (app reload/backgrounded) — retry once the app settles.',
|
|
16
|
+
METRO_UNREACHABLE:
|
|
17
|
+
'Next: start Metro with `mm-harness start-metro` (if it is already up, check the slot WATCHER_PORT).',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
module.exports = { TEACHING_BY_ERROR_CODE };
|
|
@@ -77,6 +77,22 @@ rsync -a --delete "$RUNNER_DIR/library/recipes/" "$HARNESS_DIR/runner/recipes/"
|
|
|
77
77
|
rm -rf "$HARNESS_DIR/runner/flows"
|
|
78
78
|
rm -f "$HARNESS_DIR/runner/library.json"
|
|
79
79
|
cp -R "$RUNNER_DIR/adapters/mobile/bridge-runtime" "$HARNESS_DIR/bridge-runtime"
|
|
80
|
+
# cdp-bridge.cjs runs from the target checkout, which cannot resolve the runner's
|
|
81
|
+
# packages; vendor the bridge libraries it requires next to it.
|
|
82
|
+
node - "$RUNNER_DIR" "$HARNESS_DIR/bridge-runtime/node_modules/@farmslot" <<'NODE' || exit 1
|
|
83
|
+
const fs = require('node:fs');
|
|
84
|
+
const path = require('node:path');
|
|
85
|
+
const { createRequire } = require('node:module');
|
|
86
|
+
const [runnerDir, dest] = process.argv.slice(2);
|
|
87
|
+
const requireFromRunner = createRequire(path.join(runnerDir, 'package.json'));
|
|
88
|
+
for (const [name, dirs] of [['adapter-rn', ['bridge-runtime']], ['recipe-runner', ['cdp-broker']]]) {
|
|
89
|
+
const packageJson = requireFromRunner.resolve(`@farmslot/${name}/package.json`);
|
|
90
|
+
const target = path.join(dest, name);
|
|
91
|
+
fs.mkdirSync(target, { recursive: true });
|
|
92
|
+
fs.copyFileSync(packageJson, path.join(target, 'package.json'));
|
|
93
|
+
for (const dir of dirs) fs.cpSync(path.join(path.dirname(packageJson), dir), path.join(target, dir), { recursive: true });
|
|
94
|
+
}
|
|
95
|
+
NODE
|
|
80
96
|
chmod -R u+rwX,go+rX "$HARNESS_DIR"
|
|
81
97
|
|
|
82
98
|
add_git_exclude() {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const fs = require('node:fs');
|
|
5
|
-
const path = require('node:path');
|
|
6
5
|
const { spawn } = require('node:child_process');
|
|
7
6
|
|
|
8
7
|
const args = { port: '', out: '', err: '' };
|
|
@@ -25,7 +24,7 @@ if (!args.port || !args.out || !args.err) {
|
|
|
25
24
|
process.exit(2);
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
const forwarder =
|
|
27
|
+
const forwarder = require.resolve('@farmslot/adapter-rn/bridge-runtime/console-forwarder.cjs');
|
|
29
28
|
const errFd = fs.openSync(args.err, 'a');
|
|
30
29
|
try {
|
|
31
30
|
const child = spawn(process.execPath, [forwarder, '--port', args.port, '--out', args.out], {
|
|
@@ -28,7 +28,7 @@ PLATFORM="ios"
|
|
|
28
28
|
TARGET="$PWD"
|
|
29
29
|
SIMULATOR="${SIM_UDID:-${IOS_SIMULATOR:-booted}}"
|
|
30
30
|
ADB_SERIAL_ARG="${ADB_SERIAL:-${ANDROID_SERIAL:-}}"
|
|
31
|
-
ADB_BIN="${
|
|
31
|
+
ADB_BIN="${RECIPE_RN_ADB_PATH:-}"
|
|
32
32
|
PREFLIGHT_MODE="${MOBILE_PREFLIGHT_MODE:-fast}"
|
|
33
33
|
PORT="${WATCHER_PORT:-${METRO_PORT:-8081}}"
|
|
34
34
|
UI_ONLY=false
|
|
@@ -67,7 +67,7 @@ if [ "$PLATFORM" = "android" ]; then
|
|
|
67
67
|
printf 'Next: brew install android-platform-tools\n' >&2
|
|
68
68
|
exit 1
|
|
69
69
|
fi
|
|
70
|
-
export
|
|
70
|
+
export RECIPE_RN_ADB_PATH="$ADB_BIN"
|
|
71
71
|
fi
|
|
72
72
|
|
|
73
73
|
TARGET="$(cd "$TARGET" && pwd)"
|
|
@@ -4,13 +4,13 @@ import { spawnSync } from 'node:child_process';
|
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
|
-
import { resolveMobileToolPath } from '
|
|
7
|
+
import { resolveMobileToolPath } from '@farmslot/adapter-rn';
|
|
8
8
|
|
|
9
9
|
const require = createRequire(import.meta.url);
|
|
10
10
|
const WebSocket = require('ws');
|
|
11
|
-
const { discoverTarget, rankRuntimeCandidates } = require('
|
|
12
|
-
const { brokerSocketPath, createBrokerClient, deviceIdFromUrl } = require('
|
|
13
|
-
const { createWSClient } = require('
|
|
11
|
+
const { discoverTarget, rankRuntimeCandidates } = require('@farmslot/adapter-rn/bridge-runtime/lib/target-discovery.cjs');
|
|
12
|
+
const { brokerSocketPath, createBrokerClient, deviceIdFromUrl } = require('@farmslot/recipe-runner/cdp-broker');
|
|
13
|
+
const { createWSClient } = require('@farmslot/adapter-rn/bridge-runtime/lib/ws-client.cjs');
|
|
14
14
|
|
|
15
15
|
async function observeRuntimeReset(port, target) {
|
|
16
16
|
const socketPath = brokerSocketPath(
|
|
@@ -6,7 +6,7 @@ PLATFORM="${PLATFORM:-ios}"
|
|
|
6
6
|
TARGET="$PWD"
|
|
7
7
|
SIMULATOR="${SIM_UDID:-${IOS_SIMULATOR:-booted}}"
|
|
8
8
|
ADB_SERIAL_ARG="${ADB_SERIAL:-${ANDROID_SERIAL:-}}"
|
|
9
|
-
ADB_BIN="${
|
|
9
|
+
ADB_BIN="${RECIPE_RN_ADB_PATH:-}"
|
|
10
10
|
MM_RESET_TEMP_ROOT=""
|
|
11
11
|
MM_RESET_STAGING_DIR=""
|
|
12
12
|
|
|
@@ -23,13 +23,14 @@ done
|
|
|
23
23
|
TARGET="$(cd "$TARGET" && pwd -P)"
|
|
24
24
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
25
|
if [ -z "$PORT" ] && command -v node >/dev/null 2>&1; then
|
|
26
|
-
PORT="$(
|
|
26
|
+
PORT="$(cd "$SCRIPT_DIR" && APP_ROOT="$TARGET" node -e "process.stdout.write(String(require('@farmslot/adapter-rn/bridge-runtime/lib/config.cjs').resolvePort()))")"
|
|
27
27
|
fi
|
|
28
28
|
PORT="${PORT:-8081}"
|
|
29
29
|
# shellcheck disable=SC1091
|
|
30
30
|
. "$SCRIPT_DIR/../shared/harness-path.sh"
|
|
31
31
|
LOG_DIR="$TARGET/$(recipe_runtime_dir)" || exit 1
|
|
32
|
-
|
|
32
|
+
command -v node >/dev/null 2>&1 || exit 0
|
|
33
|
+
FORWARDER="$(cd "$SCRIPT_DIR" && node -p "require.resolve('@farmslot/adapter-rn/bridge-runtime/console-forwarder.cjs')")" || exit 1
|
|
33
34
|
PID_FILE="$LOG_DIR/console-forwarder.pid"
|
|
34
35
|
APP_LOG_FILE="$LOG_DIR/app-console.log"
|
|
35
36
|
|
|
@@ -54,18 +54,23 @@ fi
|
|
|
54
54
|
# only ever inspect or signal a Metro listening on $PORT.
|
|
55
55
|
# shellcheck disable=SC1091
|
|
56
56
|
. "$SCRIPT_DIR/lib/metro-listener.sh"
|
|
57
|
-
|
|
57
|
+
# Metro config wrapper, launcher and log helpers ship in @farmslot/adapter-rn.
|
|
58
|
+
ADAPTER_RN_METRO_DIR="$(cd "$SCRIPT_DIR" && node -p "require('node:path').dirname(require.resolve('@farmslot/adapter-rn/metro/metro-config.cjs'))")" || {
|
|
59
|
+
echo "start-metro: @farmslot/adapter-rn is not installed next to the runner; reinstall the runner." >&2
|
|
60
|
+
exit 1
|
|
61
|
+
}
|
|
62
|
+
HARNESS_METRO_CONFIG="$ADAPTER_RN_METRO_DIR/metro-config.cjs"
|
|
58
63
|
if [ "${EXPO_OVERRIDE_METRO_CONFIG:-}" = "$HARNESS_METRO_CONFIG" ]; then
|
|
59
|
-
PRODUCT_METRO_CONFIG="${
|
|
64
|
+
PRODUCT_METRO_CONFIG="${RECIPE_RN_METRO_BASE_CONFIG:-$TARGET/metro.config.js}"
|
|
60
65
|
else
|
|
61
66
|
PRODUCT_METRO_CONFIG="${EXPO_OVERRIDE_METRO_CONFIG:-$TARGET/metro.config.js}"
|
|
62
67
|
fi
|
|
63
|
-
export
|
|
64
|
-
export
|
|
68
|
+
export RECIPE_RN_METRO_PROJECT_ROOT="$TARGET"
|
|
69
|
+
export RECIPE_RN_METRO_BASE_CONFIG="$PRODUCT_METRO_CONFIG"
|
|
65
70
|
export EXPO_OVERRIDE_METRO_CONFIG="$HARNESS_METRO_CONFIG"
|
|
66
|
-
MOBILE_METRO_REQUIRED_ENV="${MOBILE_METRO_REQUIRED_ENV:-MM_INFURA_PROJECT_ID METAMASK_BUILD_TYPE METAMASK_ENVIRONMENT}
|
|
67
|
-
if [ -n "${
|
|
68
|
-
MOBILE_METRO_REQUIRED_ENV="$MOBILE_METRO_REQUIRED_ENV
|
|
71
|
+
MOBILE_METRO_REQUIRED_ENV="${MOBILE_METRO_REQUIRED_ENV:-MM_INFURA_PROJECT_ID METAMASK_BUILD_TYPE METAMASK_ENVIRONMENT} RECIPE_RN_METRO_PROJECT_ROOT RECIPE_RN_METRO_BASE_CONFIG EXPO_OVERRIDE_METRO_CONFIG"
|
|
72
|
+
if [ -n "${RECIPE_RN_METRO_ENV_FINGERPRINT:-}" ]; then
|
|
73
|
+
MOBILE_METRO_REQUIRED_ENV="$MOBILE_METRO_REQUIRED_ENV RECIPE_RN_METRO_ENV_FINGERPRINT"
|
|
69
74
|
fi
|
|
70
75
|
|
|
71
76
|
# RECIPE_RUNTIME_DIR (relative, validated) makes runtime state per-run so jobs
|
|
@@ -75,8 +80,8 @@ mkdir -p "$LOG_DIR"
|
|
|
75
80
|
LOG_FILE="$LOG_DIR/metro.log"
|
|
76
81
|
PID_FILE="$LOG_DIR/metro.pid"
|
|
77
82
|
METRO_BUILD_ENV_FILE="$LOG_DIR/metro-build-env.sh"
|
|
78
|
-
METRO_LOG_GENERATION="$
|
|
79
|
-
METRO_LOG_COALESCER="$
|
|
83
|
+
METRO_LOG_GENERATION="$ADAPTER_RN_METRO_DIR/metro-log-generation.cjs"
|
|
84
|
+
METRO_LOG_COALESCER="$ADAPTER_RN_METRO_DIR/coalesce-metro-log.cjs"
|
|
80
85
|
|
|
81
86
|
# --- helpers ------------------------------------------------------------------
|
|
82
87
|
|
|
@@ -106,8 +111,8 @@ write_metro_build_env() {
|
|
|
106
111
|
done
|
|
107
112
|
)" || { rm -f "$temporary"; return 1; }
|
|
108
113
|
eval "$product_values"
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
required_RECIPE_RN_METRO_PROJECT_ROOT="$RECIPE_RN_METRO_PROJECT_ROOT"
|
|
115
|
+
required_RECIPE_RN_METRO_BASE_CONFIG="$RECIPE_RN_METRO_BASE_CONFIG"
|
|
111
116
|
required_EXPO_OVERRIDE_METRO_CONFIG="$EXPO_OVERRIDE_METRO_CONFIG"
|
|
112
117
|
[ "$CLEAR" = true ] && clear_value=1
|
|
113
118
|
{
|
|
@@ -322,7 +327,7 @@ else
|
|
|
322
327
|
)
|
|
323
328
|
[ -z "$METRO_WORKERS" ] || launcher_args+=(--workers "$METRO_WORKERS")
|
|
324
329
|
[ "$CLEAR" = true ] && launcher_args+=(--clear)
|
|
325
|
-
node "$
|
|
330
|
+
node "$ADAPTER_RN_METRO_DIR/launch-metro.cjs" "${launcher_args[@]}"
|
|
326
331
|
) || exit 1
|
|
327
332
|
STARTED_METRO_PID="$(cat "$PID_FILE" 2>/dev/null || true)"
|
|
328
333
|
|
|
@@ -14,10 +14,10 @@ const {
|
|
|
14
14
|
describeRequested,
|
|
15
15
|
describeTargets,
|
|
16
16
|
hasMatchingRoute,
|
|
17
|
-
} = require('
|
|
17
|
+
} = require('@farmslot/adapter-rn/bridge-runtime/lib/match-bridge-target.cjs');
|
|
18
18
|
const {
|
|
19
19
|
rankRuntimeCandidates,
|
|
20
|
-
} = require('
|
|
20
|
+
} = require('@farmslot/adapter-rn/bridge-runtime/lib/target-discovery.cjs');
|
|
21
21
|
|
|
22
22
|
const DEFAULT_MAX_POLLS = 90;
|
|
23
23
|
const DEFAULT_POLL_INTERVAL_MS = 2_000;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// the next launch refreshes every slot from it.
|
|
9
9
|
//
|
|
10
10
|
// Source files count by size + mtime, so it is cheap enough to run on every launch;
|
|
11
|
-
// the only
|
|
11
|
+
// the only files read are the vendored packages' package.json, for their versions. No
|
|
12
12
|
// Date.now()/random is used (both would break determinism).
|
|
13
13
|
import fs from 'node:fs';
|
|
14
14
|
import path from 'node:path';
|
|
@@ -25,17 +25,22 @@ export function harnessSourceFingerprint(runnerDir, adapter = 'extension') {
|
|
|
25
25
|
for (const rel of sourceDirs) {
|
|
26
26
|
collect(path.join(runnerDir, rel), runnerDir, entries);
|
|
27
27
|
}
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
// The injectors copy package files into the overlay (Extension: @farmslot/adapter-web's
|
|
29
|
+
// browser helpers; Mobile: the bridge libraries cdp-bridge.cjs requires), so those
|
|
30
|
+
// sources are overlay inputs too; label them by package so the install location
|
|
31
|
+
// does not count.
|
|
32
|
+
const vendored = adapter === 'extension'
|
|
33
|
+
? [['@farmslot/adapter-web', ['src']]]
|
|
34
|
+
: [['@farmslot/adapter-rn', ['bridge-runtime']], ['@farmslot/recipe-runner', ['cdp-broker']]];
|
|
35
|
+
for (const [name, dirs] of vendored) {
|
|
36
|
+
const packageJson = createRequire(path.join(runnerDir, 'package.json')).resolve(`${name}/package.json`);
|
|
32
37
|
const packageRoot = path.dirname(packageJson);
|
|
33
38
|
const packageEntries = [];
|
|
34
|
-
collect(path.join(packageRoot,
|
|
35
|
-
entries.push(...packageEntries.map((entry) =>
|
|
39
|
+
for (const dir of dirs) collect(path.join(packageRoot, dir), packageRoot, packageEntries);
|
|
40
|
+
entries.push(...packageEntries.map((entry) => `${name}/${entry}`));
|
|
36
41
|
// npm tarballs carry fixed mtimes, so an upgrade can keep every size and mtime:
|
|
37
42
|
// the version marks it.
|
|
38
|
-
entries.push(
|
|
43
|
+
entries.push(`${name}@${JSON.parse(fs.readFileSync(packageJson, 'utf8')).version}`);
|
|
39
44
|
}
|
|
40
45
|
entries.sort();
|
|
41
46
|
return crypto.createHash('sha256').update(entries.join('\n')).digest('hex');
|
|
@@ -15,10 +15,10 @@ import path from 'node:path';
|
|
|
15
15
|
const require = createRequire(import.meta.url);
|
|
16
16
|
const {
|
|
17
17
|
discoverTarget,
|
|
18
|
-
} = require('
|
|
18
|
+
} = require('@farmslot/adapter-rn/bridge-runtime/lib/target-discovery.cjs');
|
|
19
19
|
const {
|
|
20
20
|
deviceIdFromUrl,
|
|
21
|
-
} = require('
|
|
21
|
+
} = require('@farmslot/recipe-runner/cdp-broker');
|
|
22
22
|
|
|
23
23
|
function usage() {
|
|
24
24
|
console.error(`Usage:
|
|
@@ -60,12 +60,15 @@ fi
|
|
|
60
60
|
|
|
61
61
|
# Farmslot slot sync (requires farmslot root and sync-fixtures.sh).
|
|
62
62
|
if [ -n "$SLOT_ID" ]; then
|
|
63
|
+
# An explicit FARMSLOT_ROOT wins; otherwise the operator checkout's farm script.
|
|
63
64
|
FARMSLOT_ROOT="${FARMSLOT_ROOT:-}"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
if [ -z "$FARMSLOT_ROOT" ]; then
|
|
66
|
+
for candidate in "$HOME/dev/farmslot" "$HOME/farmslot"; do
|
|
67
|
+
[ -f "$candidate/scripts/sync-fixtures.sh" ] || continue
|
|
68
|
+
FARMSLOT_ROOT="$candidate"
|
|
69
|
+
break
|
|
70
|
+
done
|
|
71
|
+
fi
|
|
69
72
|
if [ -n "$FARMSLOT_ROOT" ] && [ -f "$FARMSLOT_ROOT/scripts/sync-fixtures.sh" ]; then
|
|
70
73
|
if bash "$FARMSLOT_ROOT/scripts/sync-fixtures.sh" --slot "$SLOT_ID" 2>/dev/null; then
|
|
71
74
|
[ -f "$CANONICAL" ] && exit 0
|
|
@@ -11,7 +11,8 @@ import { existsSync, readdirSync, rmSync } from 'node:fs';
|
|
|
11
11
|
import path from 'node:path';
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
13
|
|
|
14
|
-
import { recipeHarnessPath
|
|
14
|
+
import { recipeHarnessPath } from '@farmslot/recipe-cli/harness';
|
|
15
|
+
import { walletFixturePath } from '../../library/actions/harness-exports.mjs';
|
|
15
16
|
import { terminalRuntimeDir } from '../../library/actions/terminal/platform/runtime.mjs';
|
|
16
17
|
import { stopConsoleCollector, stopTerminalBrowser } from './lib/processes.mjs';
|
|
17
18
|
|
|
@@ -13,7 +13,8 @@ import { copyFileSync, chmodSync, existsSync, mkdirSync, readFileSync, writeFile
|
|
|
13
13
|
import path from 'node:path';
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
15
|
|
|
16
|
-
import { recipeHarnessPath, recipeRuntimeDir
|
|
16
|
+
import { recipeHarnessPath, recipeRuntimeDir } from '@farmslot/recipe-cli/harness';
|
|
17
|
+
import { walletFixturePath } from '../../library/actions/harness-exports.mjs';
|
|
17
18
|
import { terminalRuntimeDir } from '../../library/actions/terminal/platform/runtime.mjs';
|
|
18
19
|
import { isTerminalCheckout } from './lib/readiness.mjs';
|
|
19
20
|
|
package/bin/mm-harness
CHANGED
|
@@ -90,24 +90,6 @@ if [ -f "$ENSURE_DEPS" ]; then
|
|
|
90
90
|
bash "$ENSURE_DEPS" "$RUNNER_DIR"
|
|
91
91
|
fi
|
|
92
92
|
|
|
93
|
-
find_protocol_root() {
|
|
94
|
-
local start="$1"
|
|
95
|
-
local dir
|
|
96
|
-
dir="$(cd "$start" && pwd -P)"
|
|
97
|
-
while [ "$dir" != "/" ]; do
|
|
98
|
-
if [ -f "$dir/packages/recipe-runner/package.json" ] && [ -f "$dir/packages/protocol/package.json" ]; then
|
|
99
|
-
printf '%s\n' "$dir"
|
|
100
|
-
return 0
|
|
101
|
-
fi
|
|
102
|
-
if [ -f "$dir/farmslot/packages/recipe-runner/package.json" ] && [ -f "$dir/farmslot/packages/protocol/package.json" ]; then
|
|
103
|
-
printf '%s\n' "$dir/farmslot"
|
|
104
|
-
return 0
|
|
105
|
-
fi
|
|
106
|
-
dir="$(dirname "$dir")"
|
|
107
|
-
done
|
|
108
|
-
return 1
|
|
109
|
-
}
|
|
110
|
-
|
|
111
93
|
node_can_run_source_typescript() {
|
|
112
94
|
# Node refuses type-stripping for files under node_modules (ERR_UNSUPPORTED_NODE_
|
|
113
95
|
# MODULES_TYPE_STRIPPING). When this runner is installed as a dependency, the
|
|
@@ -183,20 +165,19 @@ if [ ! -f "$ENTRY_TS" ]; then
|
|
|
183
165
|
exit 1
|
|
184
166
|
fi
|
|
185
167
|
|
|
186
|
-
TSX_BIN
|
|
187
|
-
|
|
188
|
-
|
|
168
|
+
# ENTRY_TSX, not TSX_BIN: TSX_BIN is the caller's choice of runner for live
|
|
169
|
+
# adapter scripts too, so this fallback must not overwrite the exported value.
|
|
170
|
+
ENTRY_TSX="${TSX_BIN:-$RUNNER_DIR/node_modules/.bin/tsx}"
|
|
171
|
+
if [ ! -x "$ENTRY_TSX" ] && [ -x "$RUNNER_DIR/../../.bin/tsx" ]; then
|
|
172
|
+
ENTRY_TSX="$RUNNER_DIR/../../.bin/tsx"
|
|
189
173
|
fi
|
|
190
|
-
if [ ! -x "$
|
|
174
|
+
if [ ! -x "$ENTRY_TSX" ]; then
|
|
191
175
|
if [ -z "${FARMSLOT_ROOT:-}" ] && [ -f "$RUNNER_DIR/.farmslot-root" ]; then
|
|
192
176
|
FARMSLOT_ROOT="$(cat "$RUNNER_DIR/.farmslot-root")"
|
|
193
177
|
fi
|
|
194
|
-
if [ -z "${FARMSLOT_ROOT:-}" ]; then
|
|
195
|
-
FARMSLOT_ROOT="$(find_protocol_root "$RUNNER_DIR" || find_protocol_root "$PWD" || true)"
|
|
196
|
-
fi
|
|
197
178
|
if [ -n "${FARMSLOT_ROOT:-}" ]; then
|
|
198
179
|
FARMSLOT_ROOT="$(cd "$FARMSLOT_ROOT" && pwd -P)"
|
|
199
|
-
|
|
180
|
+
ENTRY_TSX="$FARMSLOT_ROOT/node_modules/.bin/tsx"
|
|
200
181
|
fi
|
|
201
182
|
fi
|
|
202
183
|
|
|
@@ -204,8 +185,8 @@ if node_can_run_source_typescript; then
|
|
|
204
185
|
exec node --no-warnings "$ENTRY_TS" "$@"
|
|
205
186
|
fi
|
|
206
187
|
|
|
207
|
-
if [ -x "$
|
|
208
|
-
exec "$
|
|
188
|
+
if [ -x "$ENTRY_TSX" ]; then
|
|
189
|
+
exec "$ENTRY_TSX" "$ENTRY_TS" "$@"
|
|
209
190
|
fi
|
|
210
191
|
|
|
211
192
|
echo "mm-harness: source checkout requires dist/mm-harness-cli.js, Node.js TypeScript type stripping, or a local tsx binary." >&2
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
function checkoutHas(target, relative) {
|
|
4
|
+
return fs.existsSync(path.join(target, relative));
|
|
5
|
+
}
|
|
6
|
+
function checkoutHasDir(target, relative) {
|
|
7
|
+
try {
|
|
8
|
+
return fs.statSync(path.join(target, relative)).isDirectory();
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
checkoutHas,
|
|
15
|
+
checkoutHasDir
|
|
16
|
+
};
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import {
|
|
5
5
|
collectorMatches,
|
|
6
6
|
collectorOwnerMarker,
|
|
7
|
+
collectorStatus,
|
|
7
8
|
isLegacyCollector,
|
|
8
9
|
isOwnedCollector,
|
|
9
10
|
isPriorInstallCollector,
|
|
@@ -80,6 +81,17 @@ async function stopProcess(pid) {
|
|
|
80
81
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
81
82
|
}
|
|
82
83
|
}
|
|
84
|
+
async function verifyOwnedCollectorControl(capture, control) {
|
|
85
|
+
const status = collectorStatus({
|
|
86
|
+
pidFile: capture.pidFile,
|
|
87
|
+
extensionLog: capture.extensionLog,
|
|
88
|
+
marker: collectorOwnerMarker(path.dirname(capture.pidFile)),
|
|
89
|
+
cdpPort: capture.cdpPort
|
|
90
|
+
});
|
|
91
|
+
if (!status.ok) return { ok: false, detail: status.detail };
|
|
92
|
+
const result = await control();
|
|
93
|
+
return { ok: result.ok, detail: result.ok ? `${status.detail}; ${result.detail}` : result.detail };
|
|
94
|
+
}
|
|
83
95
|
const ROTATE_LOG_BYTES = 32 * 1024 * 1024;
|
|
84
96
|
function rotateLargeLog(file) {
|
|
85
97
|
if (fileSize(file) < ROTATE_LOG_BYTES) return;
|
|
@@ -118,5 +130,6 @@ function containsAttachment(from) {
|
|
|
118
130
|
export {
|
|
119
131
|
COLLECTOR_SCRIPT,
|
|
120
132
|
ROTATE_LOG_BYTES,
|
|
121
|
-
ensureConsoleCollector
|
|
133
|
+
ensureConsoleCollector,
|
|
134
|
+
verifyOwnedCollectorControl
|
|
122
135
|
};
|
|
@@ -5,10 +5,11 @@ const coreActions = {
|
|
|
5
5
|
"metamask.perps.close_positions",
|
|
6
6
|
"metamask.perps.start_state",
|
|
7
7
|
"metamask.perps.read_snapshot",
|
|
8
|
-
"metamask.perps.read_account"
|
|
8
|
+
"metamask.perps.read_account",
|
|
9
|
+
"metamask.perps.quote_fees"
|
|
9
10
|
],
|
|
10
|
-
// read_account
|
|
11
|
-
liveOnly: ["metamask.perps.read_account"],
|
|
11
|
+
// read_account and quote_fees are Core's alone, and only its live adapter implements them.
|
|
12
|
+
liveOnly: ["metamask.perps.read_account", "metamask.perps.quote_fees"],
|
|
12
13
|
tsxLiveScripts: {
|
|
13
14
|
env: async (projectRoot, tempDir) => (await import("./live-script-env.js")).coreLiveScriptEnv(projectRoot, tempDir)
|
|
14
15
|
},
|
|
@@ -1,8 +1,35 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { coreDependencyBlock } from "../../commands/core-readiness.js";
|
|
4
|
+
import { resolveLiveTsx } from "../../live-tsx.js";
|
|
3
5
|
const coreReadiness = {
|
|
4
|
-
compatibilityMode: (target) => fs.existsSync(path.join(target, "packages/perps-controller/src/index.ts")) ? "headless controller (no bridge)" : "unsupported/no bridge"
|
|
6
|
+
compatibilityMode: (target) => fs.existsSync(path.join(target, "packages/perps-controller/src/index.ts")) ? "headless controller (no bridge)" : "unsupported/no bridge",
|
|
7
|
+
checks: (target) => [coreControllerActionsCheck(target)]
|
|
5
8
|
};
|
|
9
|
+
function coreControllerActionsCheck(target) {
|
|
10
|
+
const block = coreDependencyBlock(target);
|
|
11
|
+
if (block) {
|
|
12
|
+
return {
|
|
13
|
+
id: "core-controller-actions",
|
|
14
|
+
status: "fail",
|
|
15
|
+
// A checkout with no dependencies installed is reported, not failed: the
|
|
16
|
+
// runtime check already says it is not ready and how to install. Once
|
|
17
|
+
// dependencies are installed, an action that still cannot run fails doctor.
|
|
18
|
+
required: block.code !== "CORE_DEPS_MISSING",
|
|
19
|
+
message: `metamask.perps.* actions cannot run: ${block.message}`,
|
|
20
|
+
detail: block.code,
|
|
21
|
+
userAction: block.userAction
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const runner = resolveLiveTsx(target);
|
|
25
|
+
return {
|
|
26
|
+
id: "core-controller-actions",
|
|
27
|
+
status: "pass",
|
|
28
|
+
required: true,
|
|
29
|
+
message: "metamask.perps.* actions can run.",
|
|
30
|
+
detail: runner ? `tsx (${runner.source}): ${runner.bin}` : void 0
|
|
31
|
+
};
|
|
32
|
+
}
|
|
6
33
|
export {
|
|
7
34
|
coreReadiness
|
|
8
35
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { isRecord } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { coreDependencyBlock } from "../../commands/core-readiness.js";
|
|
2
|
-
import { isRecord } from "../../commands/parse-args.js";
|
|
3
3
|
const coreRun = {
|
|
4
4
|
async dependencyBlock(target, { recipe, librarySources, action }) {
|
|
5
5
|
const usesController = action !== void 0 ? actionUsesCoreController(action) : await recipeUsesCoreController(recipe, librarySources);
|
|
6
6
|
return usesController ? coreDependencyBlock(target) : null;
|
|
7
7
|
},
|
|
8
|
-
violationUserAction: (violation) => violation.code === "WALLET_STATE_REQUIRED" ? "for signing,
|
|
8
|
+
violationUserAction: (violation) => violation.code === "WALLET_STATE_REQUIRED" ? "for signing, select a wallet-fixture.json account by name or by its address; an address outside the fixture works only for read-only actions" : void 0
|
|
9
9
|
};
|
|
10
10
|
async function recipeUsesCoreController(recipe, librarySources) {
|
|
11
11
|
if (objectUsesCoreController(recipe)) return true;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { shellQuote } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import path from "node:path";
|
|
2
3
|
import { depsCheck } from "@farmslot/recipe-runner/runtime/deps-readiness";
|
|
3
4
|
import { defineAdapter } from "@farmslot/adapter-sdk";
|
|
4
|
-
import { shellQuote } from "../../commands/parse-args.js";
|
|
5
5
|
import { adapterRegistry } from "../registry.js";
|
|
6
6
|
import { coreActions } from "./actions.js";
|
|
7
7
|
import { coreHarness, corePrepare, coreRuntimeContext } from "./overlay.js";
|
|
8
8
|
import { coreReadiness } from "./readiness.js";
|
|
9
9
|
import { coreRun } from "./run.js";
|
|
10
|
+
import { coreDependencyBlock } from "../../commands/core-readiness.js";
|
|
11
|
+
import { checkoutHas, checkoutHasDir } from "../checkout-files.js";
|
|
10
12
|
const coreSurface = defineAdapter({
|
|
11
13
|
id: "core",
|
|
12
14
|
sdkVersion: 1,
|
|
@@ -15,6 +17,16 @@ const coreSurface = defineAdapter({
|
|
|
15
17
|
},
|
|
16
18
|
async runtimeStatus(target) {
|
|
17
19
|
const deps = depsCheck(path.resolve(target));
|
|
20
|
+
const block = deps.status === "current" ? coreDependencyBlock(target) : null;
|
|
21
|
+
if (block) {
|
|
22
|
+
return {
|
|
23
|
+
decision: "blocked",
|
|
24
|
+
reasonCode: block.code,
|
|
25
|
+
reasons: [`Core is headless; controller actions cannot run: ${block.message}`],
|
|
26
|
+
nextAction: block.userAction,
|
|
27
|
+
deps: deps.status
|
|
28
|
+
};
|
|
29
|
+
}
|
|
18
30
|
const ready = deps.status === "current";
|
|
19
31
|
return {
|
|
20
32
|
decision: ready ? "ready" : "install",
|
|
@@ -56,6 +68,9 @@ const coreSurface = defineAdapter({
|
|
|
56
68
|
appLogSource() {
|
|
57
69
|
return null;
|
|
58
70
|
},
|
|
71
|
+
detect: {
|
|
72
|
+
files: (target) => checkoutHasDir(target, "packages/perps-controller") && checkoutHas(target, "yarn.lock")
|
|
73
|
+
},
|
|
59
74
|
hints: {
|
|
60
75
|
launch: "mm-harness run <recipe> # run recipes against the headless core",
|
|
61
76
|
relaunch: "mm-harness verify",
|
|
@@ -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"]) {
|