@deeeed/metamask-harness 0.79.0 → 0.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -0
- package/README.md +1 -1
- package/adapters/extension/ensure-browser.sh +2 -2
- package/adapters/extension/inject.mjs +0 -1
- package/adapters/extension/launch-browser.cjs +39 -613
- package/adapters/extension/readiness.mjs +2 -5
- package/adapters/extension/reattach.sh +2 -2
- package/adapters/extension/stamp-runtime-title.cjs +1 -1
- package/adapters/manifest.json +16 -64
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +57 -1358
- package/adapters/mobile/bridge-runtime/teaching.cjs +20 -0
- package/adapters/mobile/inject.sh +16 -0
- package/adapters/mobile/launch-console-forwarder.cjs +1 -2
- package/adapters/mobile/open-device.sh +2 -2
- package/adapters/mobile/reload-app.mjs +4 -4
- package/adapters/mobile/reset-app-data.sh +1 -1
- package/adapters/mobile/start-console-forwarder.sh +3 -2
- package/adapters/mobile/start-metro.sh +17 -12
- package/adapters/mobile/wait-for-bridge.cjs +2 -2
- package/adapters/shared/harness-source-fingerprint.mjs +13 -8
- package/adapters/shared/open-debug.mjs +2 -2
- package/adapters/shared/sync-wallet-fixture.sh +8 -5
- package/adapters/terminal/cleanup.mjs +2 -1
- package/adapters/terminal/inject.mjs +2 -1
- package/adapters/terminal/launch.mjs +17 -13
- package/adapters/terminal/lib/mainnet-guard.mjs +9 -0
- package/adapters/terminal/lib/readiness.mjs +20 -12
- package/adapters/terminal/policy.mjs +35 -0
- package/adapters/terminal/verify.mjs +10 -3
- package/adapters/terminal/wallet-host.mjs +43 -225
- package/bin/mm-harness +9 -28
- package/dist/adapters/checkout-files.js +16 -0
- package/dist/adapters/console-capture.js +14 -1
- package/dist/adapters/core/actions.js +8 -4
- package/dist/adapters/core/overlay.js +1 -1
- package/dist/adapters/core/readiness.js +28 -1
- package/dist/adapters/core/run.js +2 -2
- package/dist/adapters/core/surface.js +16 -1
- package/dist/adapters/extension/actions.js +6 -2
- package/dist/adapters/extension/browser-pid.js +56 -0
- package/dist/adapters/extension/console-capture.js +1 -1
- package/dist/adapters/extension/doctor-checks.js +1 -1
- package/dist/adapters/extension/ensure-ready.js +5 -4
- package/dist/adapters/extension/extension-id.js +1 -1
- package/dist/adapters/extension/feature-flags.js +1 -1
- package/dist/adapters/extension/fixtures.js +1 -2
- package/dist/adapters/extension/launch.js +4 -5
- package/dist/adapters/extension/launched-browser.js +1 -2
- package/dist/adapters/extension/network-observer.js +14 -1
- package/dist/adapters/extension/overlay.js +1 -1
- package/dist/adapters/extension/product-config.js +1 -1
- package/dist/adapters/extension/readiness.js +1 -1
- package/dist/adapters/extension/reload.js +1 -1
- package/dist/adapters/extension/run.js +135 -14
- package/dist/adapters/extension/runtime-decision.js +2 -1
- package/dist/adapters/extension/runtime.js +9 -5
- package/dist/adapters/extension/surface.js +15 -2
- package/dist/adapters/extension/verify.js +2 -2
- package/dist/adapters/harness-freshness.js +2 -1
- package/dist/adapters/mobile/actions.js +4 -1
- package/dist/adapters/mobile/android-gfxinfo-performance.js +1 -3
- package/dist/adapters/mobile/app-identity.js +10 -0
- package/dist/adapters/mobile/doctor-checks.js +1 -1
- package/dist/adapters/mobile/fixtures.js +1 -1
- package/dist/adapters/mobile/launch.js +27 -28
- package/dist/adapters/mobile/lifecycle.js +1 -1
- package/dist/adapters/mobile/metro-env.js +9 -59
- package/dist/adapters/mobile/network-observer.js +68 -0
- package/dist/adapters/mobile/performance-observer.js +2 -4
- package/dist/adapters/mobile/prepare-target.js +1 -1
- package/dist/adapters/mobile/prepare.js +3 -4
- package/dist/adapters/mobile/provision.js +1 -1
- package/dist/adapters/mobile/readiness.js +1 -1
- package/dist/adapters/mobile/recording-target.js +15 -0
- package/dist/adapters/mobile/release-artifact-state.js +1 -1
- package/dist/adapters/mobile/reload.js +1 -1
- package/dist/adapters/mobile/run.js +39 -15
- package/dist/adapters/mobile/runtime-decision.js +2 -4
- package/dist/adapters/mobile/source-freshness.js +22 -126
- package/dist/adapters/mobile/surface.js +26 -3
- package/dist/adapters/mobile/ui.js +16 -5
- package/dist/adapters/mobile/verify.js +2 -3
- package/dist/adapters/performance/cdp-trace.js +1 -1
- package/dist/adapters/performance/device-platform.js +1 -1
- package/dist/adapters/perps-order-inputs.js +36 -0
- package/dist/adapters/proof-failure.js +11 -0
- package/dist/adapters/slot-ports.js +1 -1
- package/dist/adapters/surface.js +1 -0
- package/dist/adapters/terminal/actions.js +4 -1
- package/dist/adapters/terminal/console-capture.js +1 -1
- package/dist/adapters/terminal/doctor-checks.js +2 -0
- package/dist/adapters/terminal/launch.js +4 -1
- package/dist/adapters/terminal/overlay.js +8 -1
- package/dist/adapters/terminal/run.js +33 -5
- package/dist/adapters/terminal/surface.js +9 -1
- package/dist/adapters.js +27 -7
- package/dist/advisor-policy.js +1 -1
- package/dist/checkout-view.js +1 -2
- package/dist/cli.js +59 -21
- package/dist/command-contract.js +1 -26
- package/dist/commands/check.js +33 -10
- package/dist/commands/checklist.js +1 -1
- package/dist/commands/completion-candidates.js +6 -14
- package/dist/commands/config.js +2 -2
- package/dist/commands/core-readiness.js +12 -7
- package/dist/commands/debug.js +3 -3
- package/dist/commands/device-target.js +5 -5
- package/dist/commands/doctor.js +2 -14
- package/dist/commands/domain.js +2 -2
- package/dist/commands/ensure-ready.js +1 -7
- package/dist/commands/fixtures.js +5 -6
- package/dist/commands/help.js +3 -4
- package/dist/commands/launch/device.js +10 -17
- package/dist/commands/launch/extension.js +2 -8
- package/dist/commands/launch/mobile.js +1 -1
- package/dist/commands/logs.js +3 -3
- package/dist/commands/mobile-device-view.js +4 -2
- package/dist/commands/overlay.js +110 -0
- package/dist/commands/pin.js +1 -1
- package/dist/commands/pr-body.js +2 -2
- package/dist/commands/prepare.js +4 -9
- package/dist/commands/provision.js +3 -12
- package/dist/commands/recipe-advice.js +1 -2
- package/dist/commands/recipe-quality.js +2 -3
- package/dist/commands/resolve-extension.js +1 -7
- package/dist/commands/review.js +4 -4
- package/dist/commands/runtime-decision.js +1 -6
- package/dist/commands/runtime-health.js +1 -7
- package/dist/commands/runtime-launch.js +1 -13
- package/dist/commands/self-test.js +5 -8
- package/dist/commands/status-watch.js +1 -2
- package/dist/commands/status.js +2 -5
- package/dist/commands/task-init.js +2 -3
- package/dist/commands/tutorial.js +2 -2
- package/dist/commands/update.js +1 -1
- package/dist/completions-cache.js +1 -1
- package/dist/console-classifier.js +19 -0
- package/dist/doctor.js +2 -3
- package/dist/engine.js +57 -0
- package/dist/funding-execution-context.js +96 -1
- package/dist/host.js +32 -0
- package/dist/index.js +1 -6
- package/dist/live-tsx.js +49 -0
- package/dist/mm-harness-cli.js +4 -6
- package/dist/paths.js +34 -64
- package/dist/performance-observation.js +3 -5
- package/dist/progress.js +1 -1
- package/dist/recipe-assistance-context.js +6 -9
- package/dist/recipe-security.js +2 -59
- package/dist/review/knowledge.js +2 -2
- package/dist/runner.js +7 -4
- package/dist/runtime-context.js +1 -1
- package/dist/task-view.js +2 -3
- package/docs/CONTRIBUTING.md +5 -3
- package/docs/RECIPES.md +31 -3
- package/docs/cli-contract.md +2 -2
- package/docs/feature-guard.md +90 -0
- package/library/README.md +3 -1
- package/library/actions/core/perps/_controller.mjs +153 -134
- package/library/actions/core/perps/_rewards.mjs +186 -0
- package/library/actions/core/perps/close_positions.mjs +1 -1
- package/library/actions/core/perps/place_order.mjs +167 -45
- package/library/actions/core/perps/quote_fees.mjs +61 -0
- package/library/actions/core/wallet/list_accounts.mjs +14 -57
- package/library/actions/extension/feature_flags/state.mjs +1 -1
- package/library/actions/extension/perps/close_visible_position.mjs +5 -0
- package/library/actions/extension/perps/edit_margin.mjs +4 -0
- package/library/actions/extension/perps/mutation-receipt.mjs +95 -3
- package/library/actions/extension/perps/perps.mjs +320 -3
- package/library/actions/extension/perps/place_order.mjs +3 -1
- package/library/actions/extension/perps/update_position_tpsl.mjs +4 -0
- package/library/actions/extension/platform/cdp.mjs +73 -11
- package/library/actions/harness-exports.mjs +1 -6
- package/library/actions/mobile/app/network-control.mjs +6 -8
- package/library/actions/mobile/perps/perps.mjs +216 -11
- package/library/actions/mobile/perps/place_order.mjs +3 -1
- package/library/actions/mobile/perps/prepare_local_snapshot_endpoint.mjs +1 -1
- package/library/actions/mobile/platform/bridge.mjs +8 -8
- package/library/actions/mobile/platform/native-session-name.mjs +21 -1
- package/library/actions/mobile/platform/native-session.mjs +3 -4
- package/library/actions/mobile/platform/observe-ui.mjs +12 -6
- package/library/actions/mobile/ui/native-navigation.mjs +4 -3
- package/library/actions/mobile/wallet/native-ui.mjs +3 -2
- package/library/actions/shared/analytics/_adapter.mjs +1 -1
- package/library/actions/shared/console-findings.mjs +1 -1
- package/library/actions/shared/perps/order-policy.mjs +177 -0
- package/library/actions/shared/wallet/fixture-accounts.mjs +84 -0
- package/library/actions/terminal/app/launch.mjs +3 -2
- package/library/actions/terminal/platform/hud.mjs +2 -1
- package/library/actions/terminal/platform/page.mjs +2 -1
- package/library/actions/terminal/platform/runtime.mjs +2 -1
- package/library/actions/terminal/wallet/_signature-log.mjs +40 -161
- package/library/actions/terminal/wallet/assert_signatures.mjs +6 -12
- package/library/actions/terminal/wallet/read_signatures.mjs +10 -9
- package/library/manifests/core.action-manifest.json +87 -13
- package/library/manifests/extension.action-manifest.json +4 -0
- package/library/manifests/mobile.action-manifest.json +12 -0
- package/package.json +8 -9
- package/site/assets/help-recipes.json +1 -0
- package/adapters/extension/lib/slot-title.cjs +0 -292
- package/adapters/mobile/bridge-runtime/console-forwarder.cjs +0 -472
- package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +0 -125
- package/adapters/mobile/bridge-runtime/lib/cdp-broker.cjs +0 -1055
- package/adapters/mobile/bridge-runtime/lib/cdp-eval.cjs +0 -110
- package/adapters/mobile/bridge-runtime/lib/config.cjs +0 -61
- package/adapters/mobile/bridge-runtime/lib/console-format.cjs +0 -53
- package/adapters/mobile/bridge-runtime/lib/devtools-proxy.cjs +0 -177
- package/adapters/mobile/bridge-runtime/lib/issue-capture.cjs +0 -446
- package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +0 -84
- package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +0 -403
- package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +0 -116
- package/adapters/mobile/coalesce-metro-log.cjs +0 -24
- package/adapters/mobile/launch-metro.cjs +0 -77
- package/adapters/mobile/metro-config.cjs +0 -98
- package/adapters/mobile/metro-log-generation.cjs +0 -106
- package/adapters/terminal/lib/origin.mjs +0 -30
- package/adapters/terminal/lib/page-script.mjs +0 -246
- package/adapters/terminal/lib/strict-wallet.mjs +0 -138
- package/dist/adapters/mobile/frame-metrics.js +0 -118
- package/dist/adapters/mobile/video-recorder.js +0 -289
- package/dist/artifact-files.js +0 -92
- package/dist/checkout-lock.js +0 -149
- package/dist/cli-color.js +0 -98
- package/dist/command-journal.js +0 -308
- package/dist/commands/call.js +0 -685
- package/dist/commands/last.js +0 -60
- package/dist/commands/launch/index.js +0 -109
- package/dist/commands/list-executables.js +0 -247
- package/dist/commands/manifest.js +0 -488
- package/dist/commands/parse-args.js +0 -279
- package/dist/commands/reload.js +0 -41
- package/dist/commands/run-engine.js +0 -1340
- package/dist/commands/run-report.js +0 -241
- package/dist/commands/run.js +0 -751
- package/dist/commands/shared.js +0 -323
- package/dist/commands/stop.js +0 -60
- package/dist/devices.js +0 -100
- package/dist/discovery.js +0 -15
- package/dist/execution-provenance.js +0 -332
- package/dist/harness.js +0 -451
- package/dist/heal-bounds.js +0 -137
- package/dist/json-stream.js +0 -60
- package/dist/leaf-invoke.js +0 -19
- package/dist/library-provenance.js +0 -33
- package/dist/live-adapter-contract.js +0 -380
- package/dist/metamask-action-validation.js +0 -68
- package/dist/network-observation.js +0 -290
- package/dist/recording-target.js +0 -120
- package/dist/run-diagnostics.js +0 -364
- package/dist/run-recording.js +0 -481
- package/dist/runtime-proof.js +0 -90
- package/library/actions/mobile/platform/tool-paths.mjs +0 -123
package/dist/commands/last.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import { getAdapterSurface } from "../../adapters/surface.js";
|
|
3
|
-
import {
|
|
4
|
-
ADAPTER_DETECT_NEXT,
|
|
5
|
-
checkoutBusyOut,
|
|
6
|
-
EXIT,
|
|
7
|
-
flag,
|
|
8
|
-
parseFlags,
|
|
9
|
-
resolveAdapter,
|
|
10
|
-
str,
|
|
11
|
-
targetOf,
|
|
12
|
-
usageOut
|
|
13
|
-
} from "../shared.js";
|
|
14
|
-
import { parseHeal } from "../../heal-bounds.js";
|
|
15
|
-
import { acquireCheckoutLock } from "../../checkout-lock.js";
|
|
16
|
-
import { JsonStreamWriter } from "../../json-stream.js";
|
|
17
|
-
import { shellQuote } from "./quote.js";
|
|
18
|
-
const LAUNCH_BOOLEANS = /* @__PURE__ */ new Set([
|
|
19
|
-
"build",
|
|
20
|
-
"watch",
|
|
21
|
-
"verify",
|
|
22
|
-
"sidepanel",
|
|
23
|
-
"fullscreen",
|
|
24
|
-
"runway",
|
|
25
|
-
"clearMetro",
|
|
26
|
-
"json",
|
|
27
|
-
"jsonStream",
|
|
28
|
-
"freshProfile",
|
|
29
|
-
"headless",
|
|
30
|
-
"headful"
|
|
31
|
-
]);
|
|
32
|
-
async function handleLaunch(argv) {
|
|
33
|
-
const { options } = parseFlags(argv, LAUNCH_BOOLEANS);
|
|
34
|
-
const json = flag(options, "json");
|
|
35
|
-
const stream = new JsonStreamWriter("launch", flag(options, "jsonStream"));
|
|
36
|
-
const jsonOutput = json && !stream.enabled;
|
|
37
|
-
const restoreStdout = stream.isolateStdout();
|
|
38
|
-
const target = targetOf(options);
|
|
39
|
-
try {
|
|
40
|
-
let exitCode;
|
|
41
|
-
if (!fs.existsSync(target)) {
|
|
42
|
-
exitCode = await handleLaunchLocked(argv, stream);
|
|
43
|
-
} else {
|
|
44
|
-
const lock = acquireCheckoutLock(target, "launch");
|
|
45
|
-
if ("message" in lock) {
|
|
46
|
-
const userAction = `wait for the current owner, or inspect ${lock.path} if its process has exited`;
|
|
47
|
-
stream.error({ code: "SANDBOX_BUSY", message: lock.message, userAction });
|
|
48
|
-
exitCode = checkoutBusyOut(jsonOutput, "launch", lock.message, lock.path);
|
|
49
|
-
} else {
|
|
50
|
-
try {
|
|
51
|
-
exitCode = await handleLaunchLocked(argv, stream);
|
|
52
|
-
} finally {
|
|
53
|
-
lock.release();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
stream.complete(exitCode === EXIT.ok ? "pass" : "fail", exitCode);
|
|
58
|
-
return exitCode;
|
|
59
|
-
} catch (error) {
|
|
60
|
-
const exitCode = error !== null && typeof error === "object" && "exitCode" in error && typeof error.exitCode === "number" ? error.exitCode : EXIT.runtime;
|
|
61
|
-
stream.error({
|
|
62
|
-
code: exitCode === EXIT.usage ? "CLI_USAGE_ERROR" : "LAUNCH_FAILED",
|
|
63
|
-
message: error instanceof Error ? error.message : String(error),
|
|
64
|
-
userAction: `mm-harness doctor --target ${shellQuote(target)} --json`
|
|
65
|
-
});
|
|
66
|
-
stream.complete("fail", exitCode);
|
|
67
|
-
throw error;
|
|
68
|
-
} finally {
|
|
69
|
-
restoreStdout();
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
async function handleLaunchLocked(argv, stream) {
|
|
73
|
-
const { positional, options } = parseFlags(argv, LAUNCH_BOOLEANS);
|
|
74
|
-
const json = flag(options, "json");
|
|
75
|
-
const jsonOutput = json && !stream.enabled;
|
|
76
|
-
const machine = json || stream.enabled;
|
|
77
|
-
const target = targetOf(options);
|
|
78
|
-
const heal = parseHeal(options, "auto");
|
|
79
|
-
if (typeof heal !== "string") return launchUsage(jsonOutput, stream, heal.error, "use --heal off|infra-only|auto");
|
|
80
|
-
const posToken = positional[0];
|
|
81
|
-
const mobileTargetToken = posToken === "ios" || posToken === "android" ? posToken : void 0;
|
|
82
|
-
const platformFlag = str(options, "platform");
|
|
83
|
-
const platformMobileToken = platformFlag === "ios" || platformFlag === "android" ? platformFlag : void 0;
|
|
84
|
-
const mobileTarget = mobileTargetToken ?? platformMobileToken;
|
|
85
|
-
const adapterHint = mobileTarget ? "mobile" : void 0;
|
|
86
|
-
const adapter = resolveAdapter(options, target, adapterHint);
|
|
87
|
-
if (!adapter) {
|
|
88
|
-
return launchUsage(jsonOutput, stream, `could not detect the MetaMask repo type for ${target}`, ADAPTER_DETECT_NEXT);
|
|
89
|
-
}
|
|
90
|
-
stream.phase("resolve", { target, adapter, platform: mobileTarget ?? null });
|
|
91
|
-
return getAdapterSurface(adapter).launch({
|
|
92
|
-
adapter,
|
|
93
|
-
target,
|
|
94
|
-
options,
|
|
95
|
-
mobileTarget,
|
|
96
|
-
heal,
|
|
97
|
-
jsonOutput,
|
|
98
|
-
machine,
|
|
99
|
-
stream,
|
|
100
|
-
usage: (message, userAction) => launchUsage(jsonOutput, stream, message, userAction)
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
function launchUsage(json, stream, message, userAction) {
|
|
104
|
-
stream.error({ code: "USAGE", message, userAction });
|
|
105
|
-
return usageOut(json, "launch", message, userAction);
|
|
106
|
-
}
|
|
107
|
-
export {
|
|
108
|
-
handleLaunch
|
|
109
|
-
};
|
|
@@ -1,247 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { resolveActionManifest } from "../manifest.js";
|
|
4
|
-
import { importRecipeProtocol } from "../paths.js";
|
|
5
|
-
import { color } from "../cli-color.js";
|
|
6
|
-
import { EXIT } from "./shared.js";
|
|
7
|
-
import { optionFlag, optionString, optionStrings, resolveAdapter, shellQuoteArg } from "./parse-args.js";
|
|
8
|
-
import { actionDomain, describeManifestActions, renderHumanActionCatalog } from "./manifest.js";
|
|
9
|
-
import { shortActionNames } from "@farmslot/recipe-cli";
|
|
10
|
-
import {
|
|
11
|
-
describeRunnableRecipe,
|
|
12
|
-
listRunnableRecipes,
|
|
13
|
-
resolveMetaMaskLibrarySources
|
|
14
|
-
} from "./run-engine.js";
|
|
15
|
-
const recipeDomain = (name) => name.includes(".") ? name.split(".")[0].replaceAll("_", "-") : "general";
|
|
16
|
-
function catalogDescription(description) {
|
|
17
|
-
if (!description) return "";
|
|
18
|
-
const firstSentence = description.match(/^.*?[.!?](?:\s|$)/u)?.[0]?.trim() ?? description;
|
|
19
|
-
return firstSentence.length <= 180 ? firstSentence : `${firstSentence.slice(0, 177).trimEnd()}\u2026`;
|
|
20
|
-
}
|
|
21
|
-
async function handleListExecutables(command, options) {
|
|
22
|
-
const json = optionFlag(options, "json");
|
|
23
|
-
const { adapter } = resolveAdapter(options);
|
|
24
|
-
const domainFilter = optionString(options, "domain")?.replaceAll("_", "-");
|
|
25
|
-
const sourceFilter = optionString(options, "source");
|
|
26
|
-
const sort = optionString(options, "sort") ?? (json ? "name" : "domain");
|
|
27
|
-
const groupKey = (entry, domain) => sort === "library" ? entry.source : sort === "domain" ? domain : "";
|
|
28
|
-
const select = (available2, domainOf) => available2.filter((entry) => (!domainFilter || domainOf(entry) === domainFilter) && (!sourceFilter || entry.source === sourceFilter)).sort((left, right) => groupKey(left, domainOf(left)).localeCompare(groupKey(right, domainOf(right))) || left.name.localeCompare(right.name));
|
|
29
|
-
const out = (style, text) => color(style, text, { stream: process.stdout });
|
|
30
|
-
const stylesFor = (domains) => {
|
|
31
|
-
const palette = ["label", "accent", "ok", "warn"];
|
|
32
|
-
return new Map([...new Set(domains)].sort().map((domain, index) => [domain, palette[index % palette.length]]));
|
|
33
|
-
};
|
|
34
|
-
const librarySources = await resolveMetaMaskLibrarySources(optionStrings(options, "library"));
|
|
35
|
-
const libraryLines = () => {
|
|
36
|
-
const lines = ["Libraries loaded:"];
|
|
37
|
-
for (const source of librarySources ?? []) {
|
|
38
|
-
const name = source.name ?? path.basename(source.root);
|
|
39
|
-
const kind = source.provenance?.kind === "bundled" ? "bundled" : "linked";
|
|
40
|
-
lines.push(` ${out("bold", name)} ${kind} \xB7 ${source.root}`);
|
|
41
|
-
}
|
|
42
|
-
if (domainFilter || sourceFilter) {
|
|
43
|
-
lines.push(`Filter: ${[domainFilter && `domain=${domainFilter}`, sourceFilter && `source=${sourceFilter}`].filter(Boolean).join(" ")}`);
|
|
44
|
-
}
|
|
45
|
-
return lines;
|
|
46
|
-
};
|
|
47
|
-
if (command === "run") {
|
|
48
|
-
const available2 = await listRunnableRecipes(adapter, librarySources);
|
|
49
|
-
const recipes = select(available2, (recipe) => recipeDomain(recipe.name));
|
|
50
|
-
if (json) {
|
|
51
|
-
console.log(JSON.stringify({ schemaVersion: 1, command, action: "list", adapter, recipes }, null, 2));
|
|
52
|
-
return EXIT.ok;
|
|
53
|
-
}
|
|
54
|
-
const domainStyles = stylesFor(available2.map((recipe) => recipeDomain(recipe.name)));
|
|
55
|
-
console.log(out("bold", `runnable recipes (${adapter})`));
|
|
56
|
-
for (const line of libraryLines()) console.log(line);
|
|
57
|
-
console.log(out("comment", "Inspect: mm-harness run <recipe> --describe"));
|
|
58
|
-
if (recipes.length === 0) {
|
|
59
|
-
console.log("No runnable recipes match.");
|
|
60
|
-
console.log(`Available domains: ${[...domainStyles.keys()].join(", ") || "none"}`);
|
|
61
|
-
console.log(`Available sources: ${[...new Set(available2.map((recipe) => recipe.source))].join(", ") || "none"}`);
|
|
62
|
-
}
|
|
63
|
-
const groups = /* @__PURE__ */ new Map();
|
|
64
|
-
for (const recipe of recipes) {
|
|
65
|
-
const group = groupKey(recipe, recipeDomain(recipe.name));
|
|
66
|
-
groups.set(group, [...groups.get(group) ?? [], recipe]);
|
|
67
|
-
}
|
|
68
|
-
for (const [group, entries] of groups) {
|
|
69
|
-
if (group) {
|
|
70
|
-
const label = sort === "library" ? `Library: ${group}` : group;
|
|
71
|
-
console.log(`
|
|
72
|
-
${out(sort === "domain" ? domainStyles.get(group) : "bold", label)} ${out("dim", `(${entries.length})`)}`);
|
|
73
|
-
}
|
|
74
|
-
for (const recipe of entries) {
|
|
75
|
-
const style = domainStyles.get(recipeDomain(recipe.name));
|
|
76
|
-
const shadowed = recipe.shadows.length > 0 ? ` shadows=${recipe.shadows.join(",")}` : "";
|
|
77
|
-
const variant = recipe.variant ? ` variant=${recipe.variant}` : " variant=all";
|
|
78
|
-
const summary = catalogDescription(recipe.description);
|
|
79
|
-
console.log(` ${out(style, recipe.name)} ${out("dim", `library=${recipe.source}${variant}${shadowed}`)}`);
|
|
80
|
-
if (summary) console.log(` ${summary}`);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return EXIT.ok;
|
|
84
|
-
}
|
|
85
|
-
const { manifest, actionSources } = await resolveActionManifest(
|
|
86
|
-
adapter,
|
|
87
|
-
optionString(options, "actionManifest"),
|
|
88
|
-
librarySources
|
|
89
|
-
);
|
|
90
|
-
const { getRecipeActionManifestActionNames } = await importRecipeProtocol();
|
|
91
|
-
const protocolNames = new Set(getRecipeActionManifestActionNames(manifest));
|
|
92
|
-
const available = describeManifestActions(manifest, actionSources).filter((entry) => protocolNames.has(entry.name)).sort((left, right) => left.name.localeCompare(right.name));
|
|
93
|
-
const described = select(available, actionDomain);
|
|
94
|
-
const shortByName = shortActionNames(available.map((entry) => entry.name));
|
|
95
|
-
const actions = described.map((entry) => ({
|
|
96
|
-
name: entry.name,
|
|
97
|
-
short: shortByName.get(entry.name) ?? null,
|
|
98
|
-
description: entry.description,
|
|
99
|
-
fields: entry.fields,
|
|
100
|
-
source: entry.source,
|
|
101
|
-
sourceTier: entry.sourceTier,
|
|
102
|
-
sourceManifest: entry.sourceManifest,
|
|
103
|
-
shadows: entry.shadows
|
|
104
|
-
}));
|
|
105
|
-
if (json) {
|
|
106
|
-
console.log(JSON.stringify({ schemaVersion: 1, command, action: "list", adapter, actions }, null, 2));
|
|
107
|
-
return EXIT.ok;
|
|
108
|
-
}
|
|
109
|
-
const contextLines = libraryLines();
|
|
110
|
-
if (described.length === 0) {
|
|
111
|
-
contextLines.push(`Available domains: ${[...new Set(available.map(actionDomain))].sort().join(", ") || "none"}`);
|
|
112
|
-
contextLines.push(`Available sources: ${[...new Set(available.map((entry) => entry.source))].sort().join(", ") || "none"}`);
|
|
113
|
-
}
|
|
114
|
-
console.log(renderHumanActionCatalog(described, {
|
|
115
|
-
title: `invocable actions (${adapter})`,
|
|
116
|
-
guidance: "Use: mm-harness call <name> \xB7 short names shown first where unambiguous",
|
|
117
|
-
sort,
|
|
118
|
-
domainStyles: stylesFor(available.map(actionDomain)),
|
|
119
|
-
contextLines,
|
|
120
|
-
displayName: (entry) => {
|
|
121
|
-
const short = shortByName.get(entry.name);
|
|
122
|
-
return short ? `${short} (${entry.name})` : `${entry.name} (full name only \u2014 ambiguous short)`;
|
|
123
|
-
}
|
|
124
|
-
}));
|
|
125
|
-
return EXIT.ok;
|
|
126
|
-
}
|
|
127
|
-
async function handleDescribeRecipe(recipeArg, options) {
|
|
128
|
-
const json = optionFlag(options, "json");
|
|
129
|
-
const { adapter } = resolveAdapter(options);
|
|
130
|
-
const libraryEntries = optionStrings(options, "library");
|
|
131
|
-
const directRecipePath = path.resolve(recipeArg);
|
|
132
|
-
const librarySources = await resolveMetaMaskLibrarySources(
|
|
133
|
-
libraryEntries,
|
|
134
|
-
fs.existsSync(directRecipePath) ? directRecipePath : void 0
|
|
135
|
-
);
|
|
136
|
-
const result = await describeRunnableRecipe(recipeArg, adapter, librarySources);
|
|
137
|
-
const targetEntry = optionString(options, "target");
|
|
138
|
-
const replayTarget = targetEntry ? path.resolve(targetEntry) : void 0;
|
|
139
|
-
const contextFlags = [
|
|
140
|
-
`--adapter ${adapter}`,
|
|
141
|
-
...libraryEntries?.map((entry) => `--library ${shellQuoteArg(entry)}`) ?? [],
|
|
142
|
-
...replayTarget ? [`--target ${shellQuoteArg(replayTarget)}`] : []
|
|
143
|
-
].join(" ");
|
|
144
|
-
const discoveryCommand = `mm-harness run --list ${contextFlags}`;
|
|
145
|
-
if ("notFound" in result || "unreadable" in result) {
|
|
146
|
-
const code = "notFound" in result ? "RECIPE_NOT_FOUND" : "RECIPE_UNPARSEABLE";
|
|
147
|
-
const message = "notFound" in result ? result.notFound : result.unreadable;
|
|
148
|
-
const userAction = "notFound" in result ? discoveryCommand : `fix ${shellQuoteArg(recipeArg)}, then retry: mm-harness run ${shellQuoteArg(recipeArg)} --describe ${contextFlags}`;
|
|
149
|
-
if (json) {
|
|
150
|
-
console.log(JSON.stringify({
|
|
151
|
-
schemaVersion: 1,
|
|
152
|
-
command: "run",
|
|
153
|
-
action: "describe",
|
|
154
|
-
status: "fail",
|
|
155
|
-
error: { code, message, userAction },
|
|
156
|
-
exitCode: EXIT.usage
|
|
157
|
-
}, null, 2));
|
|
158
|
-
} else {
|
|
159
|
-
console.error(`\u2717 run: ${message}
|
|
160
|
-
Next: ${userAction}`);
|
|
161
|
-
}
|
|
162
|
-
return EXIT.usage;
|
|
163
|
-
}
|
|
164
|
-
const recipe = result.recipe;
|
|
165
|
-
const parameterArgs = recipe.parameters.filter((parameter) => parameter.required && !Object.hasOwn(parameter, "default")).map((parameter) => `${parameter.name}=${shellQuoteArg(exampleParameterValue(parameter))}`);
|
|
166
|
-
const runCommand = [
|
|
167
|
-
"mm-harness run",
|
|
168
|
-
shellQuoteArg(recipeArg),
|
|
169
|
-
...parameterArgs,
|
|
170
|
-
contextFlags
|
|
171
|
-
].filter(Boolean).join(" ");
|
|
172
|
-
const nextCommand = `${runCommand} --plan`;
|
|
173
|
-
if (json) {
|
|
174
|
-
console.log(JSON.stringify({
|
|
175
|
-
schemaVersion: 1,
|
|
176
|
-
command: "run",
|
|
177
|
-
action: "describe",
|
|
178
|
-
status: "pass",
|
|
179
|
-
recipe,
|
|
180
|
-
runCommand,
|
|
181
|
-
nextCommand
|
|
182
|
-
}, null, 2));
|
|
183
|
-
return EXIT.ok;
|
|
184
|
-
}
|
|
185
|
-
const out = (style, text) => color(style, text, { stream: process.stdout });
|
|
186
|
-
console.log(out("bold", `recipe ${recipe.name}`));
|
|
187
|
-
if (recipe.title) console.log(` ${out("label", "title:")} ${recipe.title}`);
|
|
188
|
-
if (recipe.description) console.log(` ${out("label", "description:")} ${recipe.description}`);
|
|
189
|
-
console.log(` ${out("label", "adapter:")} ${recipe.adapter}`);
|
|
190
|
-
console.log(` ${out("label", "source:")} ${recipe.source} \xB7 ${recipe.file}`);
|
|
191
|
-
console.log(` ${out("label", "path:")} ${out("path", recipe.path)}`);
|
|
192
|
-
if (recipe.$schema) console.log(` ${out("label", "schema:")} ${recipe.$schema}`);
|
|
193
|
-
console.log(` ${out("label", "variant:")} ${recipe.variant ?? "all adapters"}`);
|
|
194
|
-
if (recipe.shadows.length > 0) {
|
|
195
|
-
console.log(` ${out("label", "shadows:")} ${recipe.shadows.join(", ")}`);
|
|
196
|
-
}
|
|
197
|
-
if (recipe.parameters.length === 0) {
|
|
198
|
-
console.log(` ${out("label", "parameters:")} none`);
|
|
199
|
-
} else {
|
|
200
|
-
console.log(` ${out("label", `parameters (${recipe.parameters.length})`)}`);
|
|
201
|
-
for (const parameter of recipe.parameters) {
|
|
202
|
-
const required = parameter.required ? " required" : "";
|
|
203
|
-
const defaultValue = Object.hasOwn(parameter, "default") ? ` default=${compactValue(parameter.default)}` : "";
|
|
204
|
-
const choices = parameter.enum ? ` choices=${compactValue(parameter.enum)}` : "";
|
|
205
|
-
const description = parameter.description ? ` \u2014 ${parameter.description}` : "";
|
|
206
|
-
console.log(
|
|
207
|
-
` ${out("cmd", parameter.name)}${parameter.type ? ` (${parameter.type})` : ""}${required}${defaultValue}${choices}${description}`
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
renderComposition("actions", recipe.actions, out);
|
|
212
|
-
renderComposition("called recipes", recipe.nestedRecipes, out);
|
|
213
|
-
if (recipe.unresolvedRecipes.length > 0) {
|
|
214
|
-
renderComposition("unresolved recipes", recipe.unresolvedRecipes, out);
|
|
215
|
-
}
|
|
216
|
-
console.log(` ${out("comment", `Run: ${runCommand}`)}`);
|
|
217
|
-
console.log(` ${out("comment", `Next: ${nextCommand}`)}`);
|
|
218
|
-
return EXIT.ok;
|
|
219
|
-
}
|
|
220
|
-
function exampleParameterValue(parameter) {
|
|
221
|
-
if (parameter.enum && parameter.enum.length > 0) return stringifyAssignmentValue(parameter.enum[0]);
|
|
222
|
-
if (parameter.type === "boolean") return "false";
|
|
223
|
-
if (parameter.type === "number" || parameter.type === "integer") return "0";
|
|
224
|
-
if (parameter.type === "array") return "[]";
|
|
225
|
-
if (parameter.type === "object") return "{}";
|
|
226
|
-
return "value";
|
|
227
|
-
}
|
|
228
|
-
function stringifyAssignmentValue(value) {
|
|
229
|
-
return typeof value === "string" ? value : JSON.stringify(value) ?? String(value);
|
|
230
|
-
}
|
|
231
|
-
function compactValue(value) {
|
|
232
|
-
const rendered = JSON.stringify(value);
|
|
233
|
-
if (rendered === void 0) return String(value);
|
|
234
|
-
return rendered.length <= 180 ? rendered : `${rendered.slice(0, 177)}\u2026`;
|
|
235
|
-
}
|
|
236
|
-
function renderComposition(label, values, out) {
|
|
237
|
-
if (values.length === 0) {
|
|
238
|
-
console.log(` ${out("label", `${label}:`)} none`);
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
console.log(` ${out("label", `${label} (${values.length})`)}`);
|
|
242
|
-
for (const value of values) console.log(` ${out("cmd", value)}`);
|
|
243
|
-
}
|
|
244
|
-
export {
|
|
245
|
-
handleDescribeRecipe,
|
|
246
|
-
handleListExecutables
|
|
247
|
-
};
|