@deeeed/metamask-harness 0.17.5 → 0.19.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 +1059 -0
- package/README.md +91 -140
- package/adapters/core/inject.sh +1 -6
- package/adapters/extension/console-tail.mjs +55 -24
- package/adapters/extension/ensure-browser.sh +6 -1
- package/adapters/extension/inject.mjs +7 -13
- package/adapters/extension/launch-browser.cjs +7 -1
- package/adapters/extension/launch-webpack.cjs +83 -0
- package/adapters/extension/launch.sh +8 -11
- package/adapters/extension/lib/chrome-args.cjs +8 -1
- package/adapters/extension/lib/macos-focus.cjs +32 -0
- package/adapters/extension/live.sh +12 -21
- package/adapters/extension/reattach.sh +1 -0
- package/adapters/extension/seed-fixture.sh +4 -12
- package/adapters/extension/sidepanel-toggle.sh +4 -1
- package/adapters/extension/stamp-runtime-title.cjs +58 -0
- package/adapters/extension/start-watch.sh +17 -4
- package/adapters/extension/stop-viewers.sh +1 -1
- package/adapters/extension/sync-webpack-dist.cjs +107 -0
- package/adapters/extension/verify.sh +2 -2
- package/adapters/manifest.json +53 -37
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +16 -0
- package/adapters/mobile/bridge-runtime/console-forwarder.cjs +1 -1
- package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +3 -1
- package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +2 -3
- package/adapters/mobile/cleanup.sh +16 -176
- package/adapters/mobile/inject.sh +91 -671
- package/adapters/mobile/launch-console-forwarder.cjs +39 -0
- package/adapters/mobile/open-device.sh +45 -7
- package/adapters/mobile/start-console-forwarder.sh +70 -0
- package/adapters/mobile/start-metro.sh +0 -41
- package/adapters/mobile/verify.sh +34 -83
- package/adapters/mobile/wait-for-bridge.sh +22 -8
- package/adapters/shared/harness-source-fingerprint.mjs +14 -12
- package/adapters/shared/resolve-slot-ports-core.mjs +17 -6
- package/adapters/shared/resolve-slot-ports.sh +17 -5
- package/adapters/shared/update-check-worker.mjs +43 -0
- package/bin/mm-harness +21 -2
- package/dist/adapters/core/surface.js +4 -1
- package/dist/adapters/extension/console-capture.js +95 -0
- package/dist/adapters/extension/product-config.js +110 -0
- package/dist/adapters/extension/runtime-decision.js +20 -2
- package/dist/adapters/extension/surface.js +22 -3
- package/dist/adapters/harness-freshness.js +49 -0
- package/dist/adapters/mobile/perps-env.js +43 -3
- package/dist/adapters/mobile/prepare.js +39 -7
- package/dist/adapters/mobile/surface.js +5 -2
- package/dist/adapters/resolve-slot-ports.js +2 -2
- package/dist/adapters/slot-ports.js +13 -16
- package/dist/adapters.js +56 -16
- package/dist/checkout-lock.js +27 -2
- package/dist/cli-color.js +19 -0
- package/dist/cli-commands.js +1 -1
- package/dist/cli.js +7 -18
- package/dist/command-contract.js +462 -0
- package/dist/command-journal.js +263 -0
- package/dist/commands/call.js +252 -57
- package/dist/commands/check.js +10 -4
- package/dist/commands/completion-candidates.js +17 -22
- package/dist/commands/device-target.js +27 -12
- package/dist/commands/doctor.js +106 -25
- package/dist/commands/fixtures.js +142 -35
- package/dist/commands/last.js +60 -0
- package/dist/commands/launch/extension.js +40 -17
- package/dist/commands/launch/index.js +207 -63
- package/dist/commands/launch/mobile.js +2 -0
- package/dist/commands/list-executables.js +187 -29
- package/dist/commands/logs.js +8 -6
- package/dist/commands/manifest.js +286 -35
- package/dist/commands/parse-args.js +68 -4
- package/dist/commands/provision.js +10 -4
- package/dist/commands/run-engine.js +772 -264
- package/dist/commands/run-report.js +12 -3
- package/dist/commands/run.js +378 -85
- package/dist/commands/shared.js +76 -4
- package/dist/commands/status-probe.js +4 -1
- package/dist/commands/status.js +2 -1
- package/dist/commands/stop.js +7 -2
- package/dist/commands/update.js +16 -28
- package/dist/completions-cache.js +1 -1
- package/dist/doctor.js +57 -10
- package/dist/harness.js +47 -137
- package/dist/heal-bounds.js +7 -2
- package/dist/json-stream.js +57 -0
- package/dist/live-adapter-contract.js +138 -32
- package/dist/manifest.js +161 -1
- package/dist/mm-harness-cli.js +146 -73
- package/dist/paths.js +2 -5
- package/dist/recipe-security.js +178 -0
- package/dist/run-diagnostics.js +261 -0
- package/dist/run-recording.js +1 -1
- package/dist/runner.js +140 -9
- package/docs/CONTRIBUTING.md +136 -0
- package/docs/QA.md +184 -0
- package/docs/RECIPES.md +122 -0
- package/docs/SECURITY.md +88 -0
- package/library/README.md +7 -3
- package/library/actions/core/perps/_controller.mjs +43 -56
- package/library/actions/core/perps/assert_orders.mjs +6 -7
- package/library/actions/core/perps/assert_positions.mjs +6 -7
- package/library/actions/core/perps/close_orders.mjs +2 -0
- package/library/actions/core/perps/close_positions.mjs +2 -0
- package/library/actions/core/perps/ensure_orders.mjs +4 -2
- package/library/actions/core/perps/ensure_positions.mjs +4 -2
- package/library/actions/core/perps/place_order.mjs +7 -3
- package/library/actions/core/perps/read_account.mjs +2 -2
- package/library/actions/core/perps/read_orders.mjs +2 -1
- package/library/actions/core/perps/read_positions.mjs +2 -1
- package/library/actions/core/wallet/list_accounts.mjs +95 -0
- package/library/actions/extension/perps/assert_orders.mjs +2 -1
- package/library/actions/extension/perps/assert_positions.mjs +2 -1
- package/library/actions/extension/perps/perps.mjs +43 -14
- package/library/actions/extension/platform/cdp.mjs +1 -0
- package/library/actions/extension/wallet/list_accounts.mjs +41 -0
- package/library/actions/mobile/perps/assert_orders.mjs +2 -1
- package/library/actions/mobile/perps/assert_positions.mjs +2 -1
- package/library/actions/mobile/perps/perps.mjs +40 -12
- package/library/actions/mobile/wallet/list_accounts.mjs +37 -0
- package/library/library.json +1 -1
- package/library/manifests/core.action-manifest.json +1214 -396
- package/library/manifests/extension.action-manifest.json +1635 -728
- package/library/manifests/mobile.action-manifest.json +1740 -727
- package/library/recipes/app/lifecycle.android-smoke.mobile.recipe.json +63 -81
- package/library/recipes/perps/clean-market-testnet.core.recipe.json +44 -0
- package/library/recipes/perps/clean-market-testnet.recipe.json +49 -0
- package/library/recipes/perps/lifecycle.recipe.json +136 -180
- package/library/recipes/perps/order-lifecycle.core.recipe.json +71 -67
- package/library/recipes/perps/performance.background-resume.mobile.recipe.json +51 -67
- package/library/recipes/perps/performance.cold-start.mobile.recipe.json +51 -67
- package/library/recipes/perps/performance.mobile.recipe.json +37 -51
- package/library/recipes/perps/performance.warm-start.mobile.recipe.json +44 -59
- package/library/recipes/perps/read-markets.core.recipe.json +29 -31
- package/library/recipes/perps/smoke.core.recipe.json +29 -32
- package/library/recipes/perps/smoke.extension.recipe.json +41 -44
- package/library/recipes/perps/smoke.mobile.recipe.json +42 -44
- package/library/recipes/perps/trading-lifecycle.core.recipe.json +69 -65
- package/library/recipes/runner/action-validation.extension.recipe.json +312 -398
- package/library/recipes/runner/action-validation.mobile.recipe.json +316 -402
- package/library/recipes/runner/smoke.core.recipe.json +25 -0
- package/library/recipes/runner/smoke.extension.recipe.json +23 -24
- package/library/recipes/runner/smoke.mobile.recipe.json +23 -24
- package/library/recipes/wallet/smoke.extension.recipe.json +40 -0
- package/library/recipes/wallet/smoke.mobile.recipe.json +40 -0
- package/package.json +12 -5
- package/scripts/completions.sh +8 -11
- package/scripts/validate-human-outcomes.mjs +169 -0
- package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +0 -185
- package/adapters/mobile/overlay/app/dev-tools/AgenticService/AgenticService.ts.patch +0 -1662
- package/adapters/mobile/overlay/compat/README.md +0 -28
- package/adapters/mobile/overlay/compat/rn81-message-event-source.patch +0 -42
- package/adapters/shared/resolve-farmslot-ports-core.mjs +0 -3
- package/adapters/shared/resolve-farmslot-ports.mjs +0 -5
- package/adapters/shared/resolve-farmslot-ports.sh +0 -7
- package/dist/adapters/extension/harness-freshness.js +0 -39
- package/dist/commands/flows.js +0 -62
- package/docs/ADAPTER-SURFACE.md +0 -119
- package/docs/CHEATSHEET.md +0 -61
- package/docs/CLI-SPEC.md +0 -1098
- package/docs/CODE-MAP.md +0 -62
- package/docs/DEBUG-HANDOVER.md +0 -36
- package/docs/MENTAL-MODEL.md +0 -295
- package/docs/UX-PRINCIPLES.md +0 -64
- package/docs/architecture.md +0 -398
- package/docs/live-adapter-contract.md +0 -188
- package/docs/package-boundaries.md +0 -47
- package/docs/perps-flow-catalog.md +0 -235
- package/docs/recipe-libraries.md +0 -301
- package/docs/runtime-file-conventions.md +0 -36
- package/library/flows/perps.flows.json +0 -64
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { readCommandJournal } from "../command-journal.js";
|
|
2
|
+
import { EXIT } from "./shared.js";
|
|
3
|
+
import {
|
|
4
|
+
optionFlag,
|
|
5
|
+
optionString,
|
|
6
|
+
shellQuote,
|
|
7
|
+
targetPath
|
|
8
|
+
} from "./parse-args.js";
|
|
9
|
+
async function handleLast({ options }) {
|
|
10
|
+
const target = targetPath(options);
|
|
11
|
+
const { file, record } = readCommandJournal(target, optionString(options, "runtimeDir"));
|
|
12
|
+
const json = optionFlag(options, "json");
|
|
13
|
+
if (!record) {
|
|
14
|
+
const message = `no resumability journal exists for ${target}`;
|
|
15
|
+
const userAction = "run a proof or runtime command in this checkout, then re-run mm-harness last --json";
|
|
16
|
+
if (json) {
|
|
17
|
+
console.log(JSON.stringify({
|
|
18
|
+
schemaVersion: 1,
|
|
19
|
+
command: "last",
|
|
20
|
+
target,
|
|
21
|
+
journalPath: file,
|
|
22
|
+
status: "fail",
|
|
23
|
+
exitCode: EXIT.runtime,
|
|
24
|
+
error: { code: "LAST_NOT_FOUND", message, userAction }
|
|
25
|
+
}, null, 2));
|
|
26
|
+
} else {
|
|
27
|
+
console.error(`\u2717 mm-harness last: ${message}
|
|
28
|
+
Next: ${userAction}`);
|
|
29
|
+
}
|
|
30
|
+
return EXIT.runtime;
|
|
31
|
+
}
|
|
32
|
+
if (json) {
|
|
33
|
+
console.log(JSON.stringify({
|
|
34
|
+
schemaVersion: 1,
|
|
35
|
+
command: "last",
|
|
36
|
+
target,
|
|
37
|
+
journalPath: file,
|
|
38
|
+
status: "pass",
|
|
39
|
+
exitCode: EXIT.ok,
|
|
40
|
+
last: record
|
|
41
|
+
}, null, 2));
|
|
42
|
+
} else {
|
|
43
|
+
const end = record.finishedAt ?? "still running or interrupted";
|
|
44
|
+
console.log(`${record.verdict.toUpperCase()} ${record.command} (exit ${record.exitCode ?? "pending"})`);
|
|
45
|
+
console.log(`command: mm-harness ${record.command}${record.args.length > 0 ? ` ${record.args.map(shellQuote).join(" ")}` : ""}`);
|
|
46
|
+
console.log(`started: ${record.startedAt}`);
|
|
47
|
+
console.log(`finished: ${end}`);
|
|
48
|
+
if (record.evidencePaths.length > 0) {
|
|
49
|
+
console.log("evidence:");
|
|
50
|
+
for (const evidence of record.evidencePaths) console.log(` ${evidence}`);
|
|
51
|
+
} else {
|
|
52
|
+
console.log("evidence: none recorded");
|
|
53
|
+
}
|
|
54
|
+
console.log(`journal: ${file}`);
|
|
55
|
+
}
|
|
56
|
+
return EXIT.ok;
|
|
57
|
+
}
|
|
58
|
+
export {
|
|
59
|
+
handleLast
|
|
60
|
+
};
|
|
@@ -3,13 +3,15 @@ import http from "node:http";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { depsCheck } from "@farmslot/recipe-harness/runtime/deps-readiness";
|
|
6
|
+
import { colorHumanMessage } from "../../cli-color.js";
|
|
6
7
|
import { recipeHarnessPath, recipeRuntimeDir, runnerDir } from "../../paths.js";
|
|
7
8
|
import { extensionIdFromKey } from "../../adapters/extension/extension-id.js";
|
|
9
|
+
import { extensionProductConfigBlock } from "../../adapters/extension/product-config.js";
|
|
8
10
|
import { isExtensionDistStale } from "../../adapters/extension/runtime-decision.js";
|
|
9
11
|
import { checkExtensionRuntimeHealth } from "../../adapters/extension/runtime.js";
|
|
10
|
-
import {
|
|
12
|
+
import { ensureHarnessFresh } from "../../adapters/harness-freshness.js";
|
|
11
13
|
import { stopExtensionWatcher } from "../../adapters/slot-ports.js";
|
|
12
|
-
import { spawnScriptStreaming } from "../shared.js";
|
|
14
|
+
import { EXIT, spawnScriptStreaming } from "../shared.js";
|
|
13
15
|
function extensionDepsBlock(target) {
|
|
14
16
|
if (!fs.existsSync(path.join(target, "package.json"))) return null;
|
|
15
17
|
const deps = depsCheck(target);
|
|
@@ -30,18 +32,32 @@ function installExtensionDeps(target) {
|
|
|
30
32
|
return spawnScriptStreaming(installScript, ["--target", target], target);
|
|
31
33
|
}
|
|
32
34
|
async function launchExtension(target, tier, wantWatch, displayMode = "fullscreen") {
|
|
33
|
-
|
|
35
|
+
if (process.env.CHROME_USER_DATA_DIR) {
|
|
36
|
+
process.env.CHROME_USER_DATA_DIR = path.resolve(process.env.CHROME_USER_DATA_DIR);
|
|
37
|
+
}
|
|
38
|
+
const reusable = !wantWatch && tier !== "build" && await extensionRuntimeReusable(target);
|
|
39
|
+
if (!reusable) {
|
|
40
|
+
const block = extensionProductConfigBlock(target);
|
|
41
|
+
if (block) {
|
|
42
|
+
return {
|
|
43
|
+
status: EXIT.infra,
|
|
44
|
+
output: `EXTENSION_PRODUCT_CONFIG_REQUIRED: ${block.message}
|
|
45
|
+
Next: ${block.userAction}`
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
await ensureHarnessFresh(target, "extension");
|
|
34
50
|
if (wantWatch) {
|
|
35
51
|
const startWatchSh = path.join(runnerDir, "adapters/extension/start-watch.sh");
|
|
36
52
|
const watchArgs = ["--target", target];
|
|
37
53
|
if (process.env.WATCHER_PORT) watchArgs.push("--watcher-port", process.env.WATCHER_PORT);
|
|
38
|
-
console.error(`\u2192 extension watch \u2014 webpack :${process.env.WATCHER_PORT ?? "default"} (output streams below)`);
|
|
54
|
+
console.error(colorHumanMessage(`\u2192 extension watch \u2014 webpack :${process.env.WATCHER_PORT ?? "default"} (output streams below)`));
|
|
39
55
|
return spawnScriptStreaming(startWatchSh, watchArgs, target);
|
|
40
56
|
}
|
|
41
57
|
if (tier === "build") {
|
|
42
58
|
return extensionRebuild(target);
|
|
43
59
|
}
|
|
44
|
-
if (
|
|
60
|
+
if (reusable) {
|
|
45
61
|
return extensionReattach(target, displayMode);
|
|
46
62
|
}
|
|
47
63
|
return extensionRebuild(target);
|
|
@@ -49,12 +65,16 @@ async function launchExtension(target, tier, wantWatch, displayMode = "fullscree
|
|
|
49
65
|
async function extensionRuntimeReusable(target) {
|
|
50
66
|
const cdpPort = process.env.CDP_PORT;
|
|
51
67
|
if (!cdpPort) return false;
|
|
52
|
-
if (!cdpOwnedByExpectedRuntime(cdpPort, target)) return false;
|
|
53
|
-
if (!await cdpVersionReachable(cdpPort)) return false;
|
|
54
|
-
if (!await cdpHasExpectedExtensionTarget(cdpPort, target)) return false;
|
|
55
|
-
if (!await cdpRuntimeHealthy(cdpPort, target)) return false;
|
|
56
68
|
if (isExtensionDistStale(target)) return false;
|
|
57
|
-
|
|
69
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
70
|
+
const reachable = await cdpVersionReachable(cdpPort);
|
|
71
|
+
const owned = reachable && cdpOwnedByExpectedRuntime(cdpPort, target);
|
|
72
|
+
const targetPresent = owned && await cdpHasExpectedExtensionTarget(cdpPort, target);
|
|
73
|
+
const healthy = targetPresent && await cdpRuntimeHealthy(cdpPort, target);
|
|
74
|
+
if (healthy) return true;
|
|
75
|
+
if (attempt < 2) await new Promise((resolve) => setTimeout(resolve, 250));
|
|
76
|
+
}
|
|
77
|
+
return false;
|
|
58
78
|
}
|
|
59
79
|
function expectedChromeProfile(target) {
|
|
60
80
|
const profileName = process.env.RECIPE_CHROME_PROFILE_NAME || "chrome-profile";
|
|
@@ -170,12 +190,15 @@ function cdpHasExpectedExtensionTarget(port, target) {
|
|
|
170
190
|
});
|
|
171
191
|
}
|
|
172
192
|
async function cdpRuntimeHealthy(port, target) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
193
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
194
|
+
try {
|
|
195
|
+
const report = await checkExtensionRuntimeHealth(target, Number(port), { pageMode: "home-or-sidepanel" });
|
|
196
|
+
if (report.status === "PASS") return true;
|
|
197
|
+
} catch {
|
|
198
|
+
}
|
|
199
|
+
if (attempt < 2) await new Promise((resolve) => setTimeout(resolve, 250));
|
|
178
200
|
}
|
|
201
|
+
return false;
|
|
179
202
|
}
|
|
180
203
|
async function extensionReattach(target, displayMode = "fullscreen") {
|
|
181
204
|
const reattachScript = recipeHarnessPath(target, "extension", "scripts", "reattach.sh");
|
|
@@ -183,7 +206,7 @@ async function extensionReattach(target, displayMode = "fullscreen") {
|
|
|
183
206
|
if (process.env.CDP_PORT) reattachArgs.push("--cdp-port", process.env.CDP_PORT);
|
|
184
207
|
if (process.env.WATCHER_PORT) reattachArgs.push("--watcher-port", process.env.WATCHER_PORT);
|
|
185
208
|
if (process.env.EXTENSION_START_URL) reattachArgs.push("--start-url", process.env.EXTENSION_START_URL);
|
|
186
|
-
console.error(`\u2192 extension quick reattach \u2014 reload in place \xB7 CDP :${process.env.CDP_PORT ?? "default"} (no rebuild, no relaunch)`);
|
|
209
|
+
console.error(colorHumanMessage(`\u2192 extension quick reattach \u2014 reload in place \xB7 CDP :${process.env.CDP_PORT ?? "default"} (no rebuild, no relaunch)`));
|
|
187
210
|
return spawnScriptStreaming(reattachScript, reattachArgs, target);
|
|
188
211
|
}
|
|
189
212
|
async function extensionRebuild(target) {
|
|
@@ -197,7 +220,7 @@ async function extensionRebuild(target) {
|
|
|
197
220
|
const liveArgs = ["--target", target, "--start-watch"];
|
|
198
221
|
if (process.env.CDP_PORT) liveArgs.push("--cdp-port", process.env.CDP_PORT);
|
|
199
222
|
if (process.env.EXTENSION_START_URL) liveArgs.push("--start-url", process.env.EXTENSION_START_URL);
|
|
200
|
-
console.error(`\u2192 extension quick relaunch \u2014 webpack :${process.env.WATCHER_PORT ?? "default"} \xB7 CDP :${process.env.CDP_PORT ?? "default"} (output streams below)`);
|
|
223
|
+
console.error(colorHumanMessage(`\u2192 extension quick relaunch \u2014 webpack :${process.env.WATCHER_PORT ?? "default"} \xB7 CDP :${process.env.CDP_PORT ?? "default"} (output streams below)`));
|
|
201
224
|
const result = await spawnScriptStreaming(liveScript, liveArgs, target);
|
|
202
225
|
if (result.output) {
|
|
203
226
|
try {
|