@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
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import {
|
|
2
|
+
allowlistMatch,
|
|
3
|
+
classifyConsoleRecord,
|
|
4
|
+
consoleRecords,
|
|
5
|
+
libraryRootsFromEnv,
|
|
6
|
+
loadConsoleAllowlist,
|
|
7
|
+
messageSignature
|
|
8
|
+
} from "../library/actions/shared/console-findings.mjs";
|
|
9
|
+
const consoleClassifier = {
|
|
10
|
+
records: (text) => consoleRecords(text),
|
|
11
|
+
classify: (record) => classifyConsoleRecord(record),
|
|
12
|
+
signature: (message) => messageSignature(message),
|
|
13
|
+
loadAllowlist: (libraryRoots) => loadConsoleAllowlist([...libraryRoots]),
|
|
14
|
+
match: (event, allowlist) => allowlistMatch(event, allowlist),
|
|
15
|
+
libraryRoots: () => libraryRootsFromEnv()
|
|
16
|
+
};
|
|
17
|
+
export {
|
|
18
|
+
consoleClassifier
|
|
19
|
+
};
|
package/dist/doctor.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { color } from "
|
|
3
|
+
import { color, harnessExecutable, recipeHarnessRoot, recipeRuntimeDir, readRuntimeContextField, resolveRuntimeContextPath } from "@farmslot/recipe-cli/harness";
|
|
4
4
|
import { normalizeFeatureFlagRecord } from "./feature-flags.js";
|
|
5
5
|
import { getAdapterSurface } from "./adapters/surface.js";
|
|
6
|
-
import { readRuntimeContextField, resolveRuntimeContextPath } from "./harness.js";
|
|
7
6
|
import { isPin } from "./harness-pin.js";
|
|
8
|
-
import {
|
|
7
|
+
import { readJson, runnerDir } from "./paths.js";
|
|
9
8
|
function requiredDoctorCheckSummary(checks) {
|
|
10
9
|
const required = checks.filter((check) => check.required);
|
|
11
10
|
const failed = required.filter((check) => check.status === "fail").map((check) => check.id);
|
package/dist/engine.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { resolveAdapter } from "@farmslot/recipe-cli/harness";
|
|
3
|
+
import { getAdapterSurface } from "./adapters/surface.js";
|
|
4
|
+
import { consoleClassifier } from "./console-classifier.js";
|
|
5
|
+
import {
|
|
6
|
+
authorizeTrustedMutationPlan,
|
|
7
|
+
fixturePolicyMutationBase,
|
|
8
|
+
fundingOptionsFromCli,
|
|
9
|
+
isFixturePolicyBase,
|
|
10
|
+
loadTrustedMutationBase
|
|
11
|
+
} from "./funding-execution-context.js";
|
|
12
|
+
import { resolveActionManifest, validateManifest } from "./manifest.js";
|
|
13
|
+
import { LIBRARY_ACTION_NAMESPACE, runnerDir } from "./paths.js";
|
|
14
|
+
import { metaMaskActionExecutionCapabilities } from "./recipe-security.js";
|
|
15
|
+
const metaMaskEngine = {
|
|
16
|
+
bundledLibrary: {
|
|
17
|
+
name: "metamask",
|
|
18
|
+
root: path.resolve(runnerDir, "library"),
|
|
19
|
+
actionNamespace: LIBRARY_ACTION_NAMESPACE
|
|
20
|
+
},
|
|
21
|
+
resolveActionManifest,
|
|
22
|
+
validateManifest,
|
|
23
|
+
actionCapabilities: metaMaskActionExecutionCapabilities,
|
|
24
|
+
createRunner: async (adapter, manifest, { trustedMutation, ...options }) => {
|
|
25
|
+
const { createMetaMaskRunner } = await import("./runner.js");
|
|
26
|
+
return trustedMutation === NO_PLAN_MUTATION ? createMetaMaskRunner(adapter, manifest, { ...options, suppressLibraryResolutionLogs: true }) : createMetaMaskRunner(adapter, manifest, { ...options, trustedMutation });
|
|
27
|
+
},
|
|
28
|
+
// Funding files from the run's command line, bound to the run's plan. Without
|
|
29
|
+
// them, a platform whose actions take a trusted mutation (the Extension) runs a
|
|
30
|
+
// plan with external mutations in the fixture-policy lane, where each action
|
|
31
|
+
// applies the shared order policy; any other plan runs without one.
|
|
32
|
+
trustedMutation: {
|
|
33
|
+
load: async ({ cli, ...run }) => await loadTrustedMutationBase({ ...fundingOptionsFromCli(cli), ...run }) ?? (takesTrustedMutation(cli) ? fixturePolicyMutationBase({ artifactsDir: run.artifactsDir, rootRecipe: run.rootRecipe }) : void 0),
|
|
34
|
+
authorize: async (base, plan) => {
|
|
35
|
+
if (!base || base === NO_PLAN_MUTATION) return void 0;
|
|
36
|
+
if (isFixturePolicyBase(base) && !plan.nodes.some((node) => node.capabilities.includes("external-mutation"))) {
|
|
37
|
+
return NO_PLAN_MUTATION;
|
|
38
|
+
}
|
|
39
|
+
return authorizeTrustedMutationPlan(base, plan);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
console: consoleClassifier,
|
|
43
|
+
runnerIncludes: ["src", "adapters", "library", "bin", "dist", "package.json"]
|
|
44
|
+
};
|
|
45
|
+
const NO_PLAN_MUTATION = /* @__PURE__ */ Symbol("no plan mutation");
|
|
46
|
+
function takesTrustedMutation(cli) {
|
|
47
|
+
let adapter;
|
|
48
|
+
try {
|
|
49
|
+
({ adapter } = resolveAdapter(cli));
|
|
50
|
+
} catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
return getAdapterSurface(adapter).actions.trustedMutation === true;
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
metaMaskEngine
|
|
57
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { optionString, recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
|
|
1
2
|
import { createHash } from "node:crypto";
|
|
2
3
|
import { constants as fsConstants } from "node:fs";
|
|
3
4
|
import { chmod, lstat, mkdir, open, readFile, readdir, realpath } from "node:fs/promises";
|
|
4
5
|
import os from "node:os";
|
|
5
6
|
import path from "node:path";
|
|
6
7
|
import { digestRecipeDocument } from "@farmslot/protocol";
|
|
7
|
-
import { recipeRuntimeDir } from "./paths.js";
|
|
8
8
|
const SHA256 = /^[a-f0-9]{64}$/u;
|
|
9
9
|
const INTEGER = /^(0|[1-9][0-9]{0,39})$/u;
|
|
10
10
|
const IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
@@ -35,6 +35,7 @@ const CLAIM_DIFF_FIELDS = [
|
|
|
35
35
|
"operationCounts"
|
|
36
36
|
];
|
|
37
37
|
const trustedActionContexts = /* @__PURE__ */ new WeakSet();
|
|
38
|
+
const fixturePolicySources = /* @__PURE__ */ new WeakMap();
|
|
38
39
|
const fundingSources = /* @__PURE__ */ new WeakMap();
|
|
39
40
|
const CURRENT_FUNDING_REGISTRY_SHA256 = "d4416e0e8a812a0e2f1798ae6f901a5820f7ee0b9783cfa5d515d0c7863ea80e";
|
|
40
41
|
const PREVIOUS_FUNDING_REGISTRY_SHA256 = "7e79ee2a5f7bdde0a5548208cb2eab55881575cc7d826ee5f7acdbf15d49609c";
|
|
@@ -141,7 +142,70 @@ async function loadTrustedMutationBase(options) {
|
|
|
141
142
|
});
|
|
142
143
|
return trusted;
|
|
143
144
|
}
|
|
145
|
+
const FIXTURE_POLICY_LANE = "fixture-policy";
|
|
146
|
+
const fixturePolicyMarker = (field) => sha256(`${FIXTURE_POLICY_LANE}:${field}`);
|
|
147
|
+
function fixturePolicyMutationBase(options) {
|
|
148
|
+
if (!path.isAbsolute(options.artifactsDir)) {
|
|
149
|
+
throw new Error("Runner artifactsDir must be absolute before a mutation context is created.");
|
|
150
|
+
}
|
|
151
|
+
const rootRecipeSha256 = normalizeRecipeDigest(digestRecipeDocument(options.rootRecipe));
|
|
152
|
+
const base = deepFreeze({
|
|
153
|
+
runId: sha256(canonical({ lane: FIXTURE_POLICY_LANE, artifactsDir: options.artifactsDir, rootRecipeSha256 })),
|
|
154
|
+
rootRecipeSha256,
|
|
155
|
+
requestSha256: fixturePolicyMarker("request"),
|
|
156
|
+
preflightSha256: fixturePolicyMarker("preflight"),
|
|
157
|
+
releaseProofSha256: fixturePolicyMarker("release-proof"),
|
|
158
|
+
balanceProofSha256: fixturePolicyMarker("balance-proof"),
|
|
159
|
+
fundingRequirementsSha256: fixturePolicyMarker("requirements"),
|
|
160
|
+
runtimeArtifactSha256: fixturePolicyMarker("runtime-artifact"),
|
|
161
|
+
runtimeTreeSha256: fixturePolicyMarker("runtime-tree"),
|
|
162
|
+
registrySha256: fixturePolicyMarker("registry"),
|
|
163
|
+
profileId: FIXTURE_POLICY_LANE,
|
|
164
|
+
domain: "perps",
|
|
165
|
+
client: "extension",
|
|
166
|
+
proofLane: FIXTURE_POLICY_LANE,
|
|
167
|
+
targetId: FIXTURE_POLICY_LANE,
|
|
168
|
+
subjectDigest: fixturePolicyMarker("subject"),
|
|
169
|
+
selectedIdentitySha256: "",
|
|
170
|
+
runtimeSessionId: "",
|
|
171
|
+
cdpPort: 0,
|
|
172
|
+
cdpTargetId: "",
|
|
173
|
+
extensionOrigin: "",
|
|
174
|
+
operations: [],
|
|
175
|
+
budgets: [],
|
|
176
|
+
requirements: []
|
|
177
|
+
});
|
|
178
|
+
fixturePolicySources.set(base, { artifactsDir: options.artifactsDir });
|
|
179
|
+
return base;
|
|
180
|
+
}
|
|
181
|
+
function isFixturePolicyBase(base) {
|
|
182
|
+
return base?.proofLane === FIXTURE_POLICY_LANE;
|
|
183
|
+
}
|
|
184
|
+
async function authorizeFixturePolicyPlan(base, plan) {
|
|
185
|
+
const source = fixturePolicySources.get(base);
|
|
186
|
+
if (!source) throw new Error("Fixture-policy plan authorization requires the runner-created context.");
|
|
187
|
+
const executionPlanSha256 = normalizeRecipeDigest(plan.digest);
|
|
188
|
+
await mkdir(source.artifactsDir, { recursive: true, mode: 448 });
|
|
189
|
+
const artifactsDir = await realpath(source.artifactsDir);
|
|
190
|
+
const artifactsIdentitySha256 = await directoryIdentity(artifactsDir);
|
|
191
|
+
const executionLedgerRoot = path.join(artifactsDir, "mutation-ledger");
|
|
192
|
+
await ensurePrivateDirectory(artifactsDir, executionLedgerRoot);
|
|
193
|
+
const runId = sha256(canonical({
|
|
194
|
+
lane: FIXTURE_POLICY_LANE,
|
|
195
|
+
rootRecipeSha256: base.rootRecipeSha256,
|
|
196
|
+
executionPlanSha256,
|
|
197
|
+
artifactsIdentitySha256
|
|
198
|
+
}));
|
|
199
|
+
const authorized = deepFreeze({ ...base, runId, executionPlanSha256, artifactsIdentitySha256 });
|
|
200
|
+
fixturePolicySources.set(authorized, {
|
|
201
|
+
...source,
|
|
202
|
+
executionLedgerRoot,
|
|
203
|
+
executionClaimSha256: sha256(canonical({ kind: "fixture-policy-execution-claim", runId, executionPlanSha256 }))
|
|
204
|
+
});
|
|
205
|
+
return authorized;
|
|
206
|
+
}
|
|
144
207
|
async function authorizeTrustedMutationPlan(base, plan, testIo = {}) {
|
|
208
|
+
if (isFixturePolicyBase(base)) return authorizeFixturePolicyPlan(base, plan);
|
|
145
209
|
const source = fundingSources.get(base);
|
|
146
210
|
if (!source) throw new Error("Funding plan authorization requires the original runner-verified context.");
|
|
147
211
|
const executionPlanSha256 = normalizeRecipeDigest(plan.digest);
|
|
@@ -228,6 +292,20 @@ async function authorizeTrustedMutationPlan(base, plan, testIo = {}) {
|
|
|
228
292
|
return authorized;
|
|
229
293
|
}
|
|
230
294
|
async function trustedMutationForAction(base, recipe, selectedIdentitySha256) {
|
|
295
|
+
if (isFixturePolicyBase(base)) {
|
|
296
|
+
const source2 = fixturePolicySources.get(base);
|
|
297
|
+
if (!source2?.executionLedgerRoot || !source2.executionClaimSha256) {
|
|
298
|
+
throw new Error("External mutation requires an authorized run-owned execution ledger.");
|
|
299
|
+
}
|
|
300
|
+
const trusted2 = deepFreeze({
|
|
301
|
+
...base,
|
|
302
|
+
recipeSha256: normalizeRecipeDigest(digestRecipeDocument(recipe)),
|
|
303
|
+
executionLedgerRoot: source2.executionLedgerRoot,
|
|
304
|
+
executionClaimSha256: source2.executionClaimSha256
|
|
305
|
+
});
|
|
306
|
+
trustedActionContexts.add(trusted2);
|
|
307
|
+
return trusted2;
|
|
308
|
+
}
|
|
231
309
|
if (!selectedIdentitySha256 || !SHA256.test(selectedIdentitySha256)) {
|
|
232
310
|
throw new Error(
|
|
233
311
|
"External mutation requires a successful same-run metamask.wallet.import selected identity proof. Next: run metamask.wallet.import before the mutation node."
|
|
@@ -255,6 +333,18 @@ async function trustedMutationForAction(base, recipe, selectedIdentitySha256) {
|
|
|
255
333
|
trustedActionContexts.add(trusted);
|
|
256
334
|
return trusted;
|
|
257
335
|
}
|
|
336
|
+
function fundingOptionsFromCli(options) {
|
|
337
|
+
return {
|
|
338
|
+
fundingRequest: optionString(options, "fundingRequest"),
|
|
339
|
+
fundingPreflight: optionString(options, "fundingPreflight"),
|
|
340
|
+
fundingReleaseProof: optionString(options, "fundingReleaseProof"),
|
|
341
|
+
fundingBalanceProof: optionString(options, "fundingBalanceProof")
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function trustedMutationContextExtras(context) {
|
|
345
|
+
const trusted = context.trustedMutation;
|
|
346
|
+
return trusted ? { trustedMutation: serializeTrustedMutationContext(trusted) } : void 0;
|
|
347
|
+
}
|
|
258
348
|
function serializeTrustedMutationContext(value) {
|
|
259
349
|
if (!isRecord(value) || !trustedActionContexts.has(value)) {
|
|
260
350
|
throw new Error("Live adapter refused an untrusted mutation context.");
|
|
@@ -1430,9 +1520,14 @@ function deepFreeze(value) {
|
|
|
1430
1520
|
return value;
|
|
1431
1521
|
}
|
|
1432
1522
|
export {
|
|
1523
|
+
FIXTURE_POLICY_LANE,
|
|
1433
1524
|
authorizeTrustedMutationPlan,
|
|
1525
|
+
fixturePolicyMutationBase,
|
|
1526
|
+
fundingOptionsFromCli,
|
|
1527
|
+
isFixturePolicyBase,
|
|
1434
1528
|
loadTrustedMutationBase,
|
|
1435
1529
|
selectedIdentityFromWalletImport,
|
|
1436
1530
|
serializeTrustedMutationContext,
|
|
1531
|
+
trustedMutationContextExtras,
|
|
1437
1532
|
trustedMutationForAction
|
|
1438
1533
|
};
|
package/dist/host.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { configureHarnessAdapters, configureHarnessHost } from "@farmslot/recipe-cli/harness";
|
|
4
|
+
import { adapterRegistry } from "./adapters/registry.js";
|
|
5
|
+
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
|
+
configureHarnessHost({
|
|
7
|
+
name: "mm-harness",
|
|
8
|
+
product: "MetaMask",
|
|
9
|
+
envPrefix: "MM_HARNESS",
|
|
10
|
+
recipeEnvPrefix: "METAMASK_RECIPE",
|
|
11
|
+
packageName: "@deeeed/metamask-harness",
|
|
12
|
+
packageRoot,
|
|
13
|
+
bin: "bin/mm-harness",
|
|
14
|
+
journaledCommands: [
|
|
15
|
+
"prepare",
|
|
16
|
+
"call",
|
|
17
|
+
"check",
|
|
18
|
+
"checklist",
|
|
19
|
+
"cleanup",
|
|
20
|
+
"doctor",
|
|
21
|
+
"fixtures",
|
|
22
|
+
"install",
|
|
23
|
+
"launch",
|
|
24
|
+
"runtime-launch",
|
|
25
|
+
"provision",
|
|
26
|
+
"recipe-quality",
|
|
27
|
+
"run",
|
|
28
|
+
"stop",
|
|
29
|
+
"verify"
|
|
30
|
+
]
|
|
31
|
+
});
|
|
32
|
+
configureHarnessAdapters(adapterRegistry);
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "./host.js";
|
|
1
2
|
import { createDoctorReport } from "./doctor.js";
|
|
2
3
|
import { loadActionManifest, validateManifest } from "./manifest.js";
|
|
3
4
|
import { createMetaMaskExtensionRunner, createMetaMaskMobileRunner, createMetaMaskRunner } from "./runner.js";
|
|
@@ -5,13 +6,9 @@ import {
|
|
|
5
6
|
extensionIdPath,
|
|
6
7
|
importRecipeHarnessRuntimeBrowserExtension,
|
|
7
8
|
importRecipeHarnessRuntimeCdp,
|
|
8
|
-
recipeHarnessPath,
|
|
9
9
|
walletFixturePath
|
|
10
10
|
} from "./paths.js";
|
|
11
|
-
import { captureActiveRecipeRecordingSnapshot } from "./run-recording.js";
|
|
12
|
-
import { validateRuntimeProof } from "./runtime-proof.js";
|
|
13
11
|
export {
|
|
14
|
-
captureActiveRecipeRecordingSnapshot,
|
|
15
12
|
createDoctorReport,
|
|
16
13
|
createMetaMaskExtensionRunner,
|
|
17
14
|
createMetaMaskMobileRunner,
|
|
@@ -20,8 +17,6 @@ export {
|
|
|
20
17
|
importRecipeHarnessRuntimeBrowserExtension,
|
|
21
18
|
importRecipeHarnessRuntimeCdp,
|
|
22
19
|
loadActionManifest,
|
|
23
|
-
recipeHarnessPath,
|
|
24
20
|
validateManifest,
|
|
25
|
-
validateRuntimeProof,
|
|
26
21
|
walletFixturePath
|
|
27
22
|
};
|
package/dist/live-tsx.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { accessSync, constants, existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const requireFromHarness = createRequire(import.meta.url);
|
|
5
|
+
function harnessTsxBin() {
|
|
6
|
+
try {
|
|
7
|
+
const manifest = requireFromHarness.resolve("tsx/package.json");
|
|
8
|
+
const { bin } = JSON.parse(readFileSync(manifest, "utf8"));
|
|
9
|
+
const relative = typeof bin === "string" ? bin : bin?.tsx;
|
|
10
|
+
return relative ? path.join(path.dirname(manifest), relative) : void 0;
|
|
11
|
+
} catch {
|
|
12
|
+
return void 0;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function liveTsxCandidates() {
|
|
16
|
+
const bin = harnessTsxBin();
|
|
17
|
+
return bin ? [bin] : [];
|
|
18
|
+
}
|
|
19
|
+
function isExecutable(file) {
|
|
20
|
+
try {
|
|
21
|
+
accessSync(file, constants.X_OK);
|
|
22
|
+
return true;
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function resolveOverride(override, projectRoot) {
|
|
28
|
+
if (!override.includes("/")) {
|
|
29
|
+
return (process.env.PATH ?? "").split(path.delimiter).map((dir) => path.join(path.resolve(projectRoot, dir || "."), override)).find(isExecutable);
|
|
30
|
+
}
|
|
31
|
+
const bin = path.resolve(projectRoot, override);
|
|
32
|
+
return isExecutable(bin) ? bin : void 0;
|
|
33
|
+
}
|
|
34
|
+
function resolveLiveTsx(projectRoot) {
|
|
35
|
+
const override = process.env.TSX_BIN;
|
|
36
|
+
if (override) {
|
|
37
|
+
const bin = resolveOverride(override, path.resolve(projectRoot));
|
|
38
|
+
return bin ? { bin, source: "TSX_BIN" } : null;
|
|
39
|
+
}
|
|
40
|
+
const target = path.join(path.resolve(projectRoot), "node_modules/.bin/tsx");
|
|
41
|
+
if (existsSync(target)) return { bin: target, source: "target" };
|
|
42
|
+
const harness = harnessTsxBin();
|
|
43
|
+
return harness && existsSync(harness) ? { bin: harness, source: "harness" } : null;
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
harnessTsxBin,
|
|
47
|
+
liveTsxCandidates,
|
|
48
|
+
resolveLiveTsx
|
|
49
|
+
};
|
package/dist/mm-harness-cli.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
+
import "./host.js";
|
|
1
2
|
import { spawnSync } from "node:child_process";
|
|
2
3
|
import fs from "node:fs";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { Command } from "commander";
|
|
6
|
-
import { color } from "
|
|
7
|
-
import { withCommandJournal } from "./command-journal.js";
|
|
8
|
-
import { JsonStreamWriter } from "./json-stream.js";
|
|
7
|
+
import { color, withCommandJournal, JsonStreamWriter, detectAdapter, handleCallHelp } from "@farmslot/recipe-cli/harness";
|
|
9
8
|
import { handleUpdate, maybeNudge } from "./commands/update.js";
|
|
10
9
|
import { handlePin } from "./commands/pin.js";
|
|
11
|
-
import {
|
|
10
|
+
import { metaMaskEngine } from "./engine.js";
|
|
12
11
|
import { handleHelp } from "./commands/help.js";
|
|
13
12
|
import { handleTutorial } from "./commands/tutorial.js";
|
|
14
13
|
import { handleSetupBase } from "./commands/setup-base.js";
|
|
15
14
|
import { getAdapterSurface } from "./adapters/surface.js";
|
|
16
|
-
import { detectAdapter } from "./harness.js";
|
|
17
15
|
import { configPath, hydrateLibraryPathEnv, readConfig } from "./review/knowledge.js";
|
|
18
16
|
import {
|
|
19
17
|
PUBLIC_COMMAND_CONTRACTS,
|
|
@@ -1233,6 +1231,6 @@ if (hasPassthroughHelp(rawArgv)) {
|
|
|
1233
1231
|
}
|
|
1234
1232
|
if (isCallActionHelp(rawArgv)) {
|
|
1235
1233
|
const callHelp = REAL.find((command) => command.name === "call")?.helpText ?? "";
|
|
1236
|
-
process.exit(await handleCallHelp(rawArgv.slice(1), callHelp));
|
|
1234
|
+
process.exit(await handleCallHelp(rawArgv.slice(1), callHelp, { catalog: metaMaskEngine }));
|
|
1237
1235
|
}
|
|
1238
1236
|
await program.parseAsync(process.argv);
|
package/dist/paths.js
CHANGED
|
@@ -1,43 +1,10 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
+
import { recipeRuntimeDir, recipeRuntimePath } from "@farmslot/recipe-cli/harness";
|
|
4
5
|
import { adapterRegistry } from "./adapters/registry.js";
|
|
5
6
|
const runnerDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
|
-
const pathDefaults = readPathDefaults();
|
|
7
|
-
const DEFAULT_RECIPE_RUNTIME_DIR = pathDefaults.recipeRuntimeDir;
|
|
8
|
-
const DEFAULT_RECIPE_HARNESS_ROOT = pathDefaults.recipeHarnessRoot;
|
|
9
7
|
const PREPARE_PROGRESS_ARTIFACT = "prepare/progress.json";
|
|
10
|
-
function recipeRuntimeDir() {
|
|
11
|
-
return validateRelativeRecipePath("RECIPE_RUNTIME_DIR", process.env.RECIPE_RUNTIME_DIR || DEFAULT_RECIPE_RUNTIME_DIR);
|
|
12
|
-
}
|
|
13
|
-
function recipeHarnessRoot() {
|
|
14
|
-
return validateRelativeRecipePath("RECIPE_HARNESS_ROOT", process.env.RECIPE_HARNESS_ROOT || DEFAULT_RECIPE_HARNESS_ROOT);
|
|
15
|
-
}
|
|
16
|
-
function harnessExecutable() {
|
|
17
|
-
return path.resolve(process.env.MM_HARNESS_EXECUTABLE ?? path.join(runnerDir, "bin/mm-harness"));
|
|
18
|
-
}
|
|
19
|
-
function readPathDefaults() {
|
|
20
|
-
const defaultsPath = path.join(runnerDir, "adapters/shared/path-defaults.json");
|
|
21
|
-
const parsed = JSON.parse(fs.readFileSync(defaultsPath, "utf8"));
|
|
22
|
-
return {
|
|
23
|
-
recipeRuntimeDir: validateRelativeRecipePath("recipeRuntimeDir", parsed.recipeRuntimeDir || ""),
|
|
24
|
-
recipeHarnessRoot: validateRelativeRecipePath("recipeHarnessRoot", parsed.recipeHarnessRoot || "")
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
function validateRelativeRecipePath(name, value) {
|
|
28
|
-
if (!value || path.isAbsolute(value)) throw new Error(`${name} must be a non-empty relative path: ${value}`);
|
|
29
|
-
if (!/^[A-Za-z0-9._/-]+$/u.test(value)) throw new Error(`${name} contains unsupported characters: ${value}`);
|
|
30
|
-
for (const part of value.split("/")) {
|
|
31
|
-
if (!part || part === "." || part === "..") throw new Error(`${name} contains unsafe path component: ${value}`);
|
|
32
|
-
}
|
|
33
|
-
return value;
|
|
34
|
-
}
|
|
35
|
-
function recipeRuntimePath(projectRoot, ...segments) {
|
|
36
|
-
return path.join(projectRoot, recipeRuntimeDir(), ...segments);
|
|
37
|
-
}
|
|
38
|
-
function recipeHarnessPath(projectRoot, ...segments) {
|
|
39
|
-
return path.join(projectRoot, recipeHarnessRoot(), ...segments);
|
|
40
|
-
}
|
|
41
8
|
function walletFixturePath(projectRoot) {
|
|
42
9
|
return recipeRuntimePath(projectRoot, "wallet-fixture.json");
|
|
43
10
|
}
|
|
@@ -51,42 +18,51 @@ function recipeWatchLogCandidates() {
|
|
|
51
18
|
];
|
|
52
19
|
}
|
|
53
20
|
function resolveLocalProtocolRoot() {
|
|
54
|
-
const
|
|
55
|
-
process.env.METAMASK_RUNNER_PROTOCOL_ROOT,
|
|
56
|
-
readConfiguredProtocolRoot(),
|
|
57
|
-
findProtocolRoot(runnerDir),
|
|
58
|
-
findProtocolRoot(process.cwd())
|
|
59
|
-
].filter(Boolean);
|
|
60
|
-
const root = candidates[0];
|
|
21
|
+
const root = process.env.METAMASK_RUNNER_PROTOCOL_ROOT || readConfiguredProtocolRoot();
|
|
61
22
|
return root ? path.resolve(root) : void 0;
|
|
62
23
|
}
|
|
63
|
-
function
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
);
|
|
24
|
+
function resolveFarmslotPoolDir(starts = [runnerDir, process.cwd()]) {
|
|
25
|
+
const configured = resolveLocalProtocolRoot();
|
|
26
|
+
if (configured) return path.join(configured, "pool");
|
|
27
|
+
for (const start of starts) {
|
|
28
|
+
const pool = findPoolDir(start);
|
|
29
|
+
if (pool) return pool;
|
|
69
30
|
}
|
|
70
|
-
return
|
|
31
|
+
return void 0;
|
|
71
32
|
}
|
|
33
|
+
const LIBRARY_ACTION_NAMESPACE = "metamask";
|
|
72
34
|
function readConfiguredProtocolRoot() {
|
|
73
35
|
const configPath = path.join(runnerDir, ".farmslot-root");
|
|
74
36
|
if (!fs.existsSync(configPath)) return void 0;
|
|
75
37
|
const value = fs.readFileSync(configPath, "utf8").trim();
|
|
76
38
|
return value || void 0;
|
|
77
39
|
}
|
|
78
|
-
function
|
|
40
|
+
function findPoolDir(start) {
|
|
79
41
|
let dir = path.resolve(start);
|
|
80
42
|
while (dir !== path.dirname(dir)) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
43
|
+
for (const root of [dir, path.join(dir, "farmslot")]) {
|
|
44
|
+
const pool = path.join(root, "pool");
|
|
45
|
+
if (holdsSlotPool(pool)) return pool;
|
|
46
|
+
}
|
|
84
47
|
dir = path.dirname(dir);
|
|
85
48
|
}
|
|
86
49
|
return void 0;
|
|
87
50
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
51
|
+
function holdsSlotPool(candidate) {
|
|
52
|
+
let names;
|
|
53
|
+
try {
|
|
54
|
+
names = fs.readdirSync(candidate);
|
|
55
|
+
} catch {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return names.some((name) => {
|
|
59
|
+
if (!name.endsWith(".json") || name.includes(".bak")) return false;
|
|
60
|
+
try {
|
|
61
|
+
return Array.isArray(JSON.parse(fs.readFileSync(path.join(candidate, name), "utf8"))?.slots);
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
90
66
|
}
|
|
91
67
|
function assertAdapter(adapter) {
|
|
92
68
|
const ids = adapterRegistry.list();
|
|
@@ -140,8 +116,8 @@ async function importRecipeHarnessRuntimeReactNativeBridge() {
|
|
|
140
116
|
}
|
|
141
117
|
async function importMetaMaskNativeUiProvider() {
|
|
142
118
|
return importProtocolPackage(
|
|
143
|
-
"@farmslot/
|
|
144
|
-
"packages/
|
|
119
|
+
"@farmslot/adapter-rn",
|
|
120
|
+
"packages/adapter-rn/src/index.ts"
|
|
145
121
|
);
|
|
146
122
|
}
|
|
147
123
|
async function importRecipeRunnerCli() {
|
|
@@ -176,12 +152,10 @@ function isMissingPackageError(error, packageName) {
|
|
|
176
152
|
return (code === "ERR_MODULE_NOT_FOUND" || code === "ERR_PACKAGE_PATH_NOT_EXPORTED") && error.message.includes(packageName);
|
|
177
153
|
}
|
|
178
154
|
export {
|
|
179
|
-
|
|
180
|
-
DEFAULT_RECIPE_RUNTIME_DIR,
|
|
155
|
+
LIBRARY_ACTION_NAMESPACE,
|
|
181
156
|
PREPARE_PROGRESS_ARTIFACT,
|
|
182
157
|
assertAdapter,
|
|
183
158
|
extensionIdPath,
|
|
184
|
-
harnessExecutable,
|
|
185
159
|
importMetaMaskNativeUiProvider,
|
|
186
160
|
importRecipeHarness,
|
|
187
161
|
importRecipeHarnessAppLifecycle,
|
|
@@ -192,14 +166,10 @@ export {
|
|
|
192
166
|
importRecipeRunnerCli,
|
|
193
167
|
manifestPath,
|
|
194
168
|
readJson,
|
|
195
|
-
recipeHarnessPath,
|
|
196
|
-
recipeHarnessRoot,
|
|
197
169
|
recipePath,
|
|
198
|
-
recipeRuntimeDir,
|
|
199
|
-
recipeRuntimePath,
|
|
200
170
|
recipeWatchLogCandidates,
|
|
171
|
+
resolveFarmslotPoolDir,
|
|
201
172
|
resolveLocalProtocolRoot,
|
|
202
|
-
resolveRequiredLocalProtocolRoot,
|
|
203
173
|
runnerDir,
|
|
204
174
|
walletFixturePath
|
|
205
175
|
};
|
|
@@ -4,20 +4,18 @@ import { gzip } from "node:zlib";
|
|
|
4
4
|
import { getAdapterSurface } from "./adapters/surface.js";
|
|
5
5
|
import { createExtensionPerformanceBackend } from "./adapters/extension/performance-observer.js";
|
|
6
6
|
import { TRACE_KINDS } from "./adapters/performance/cdp-trace.js";
|
|
7
|
-
import { summarizeFrames } from "
|
|
7
|
+
import { summarizeFrames } from "@farmslot/adapter-rn";
|
|
8
8
|
import { summarizeJavaScriptTasks } from "./adapters/performance/js-task-metrics.js";
|
|
9
9
|
import {
|
|
10
10
|
indexArtifactManifest,
|
|
11
11
|
readContainedJsonArtifact,
|
|
12
12
|
writeContainedArtifact
|
|
13
|
-
} from "
|
|
13
|
+
} from "@farmslot/recipe-cli/harness";
|
|
14
14
|
const sessions = /* @__PURE__ */ new Map();
|
|
15
15
|
const DEFAULT_MAX_DURATION_MS = 5 * 60 * 1e3;
|
|
16
16
|
const MAX_DURATION_MS = 60 * 60 * 1e3;
|
|
17
17
|
const gzipAsync = promisify(gzip);
|
|
18
|
-
function startRunPerformanceObservation(
|
|
19
|
-
const observer = getAdapterSurface(adapter).observation?.performance;
|
|
20
|
-
if (!observer) return void 0;
|
|
18
|
+
function startRunPerformanceObservation(observer, { target, artifactsDir, env, ports }) {
|
|
21
19
|
const key = path.resolve(artifactsDir);
|
|
22
20
|
const session = {
|
|
23
21
|
observer,
|
package/dist/progress.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
|
-
import { color } from "
|
|
3
|
+
import { color } from "@farmslot/recipe-cli/harness";
|
|
4
4
|
function shouldEmitJson(explicit) {
|
|
5
5
|
if (explicit) return true;
|
|
6
6
|
const env = process.env.RECIPE_PROGRESS_JSON;
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { loadRecipeLibraries, resolveRecipeDependencies, rootResolutionRef } from "@farmslot/recipe-runner";
|
|
4
|
-
import { isSensitiveKey } from "
|
|
4
|
+
import { isSensitiveKey, CliError, describeManifestActions, isRecord, optionStrings, EXIT, resolveLibrarySources, validateRunRecipeStatic } from "@farmslot/recipe-cli/harness";
|
|
5
5
|
import { resolveActionManifest } from "./manifest.js";
|
|
6
|
-
import { describeManifestActions } from "./commands/manifest.js";
|
|
7
6
|
import { recipeComposition } from "@farmslot/recipe-cli";
|
|
8
|
-
import {
|
|
9
|
-
import { CliError, isRecord, optionStrings } from "./commands/parse-args.js";
|
|
10
|
-
import { EXIT } from "./commands/shared.js";
|
|
7
|
+
import { metaMaskEngine } from "./engine.js";
|
|
11
8
|
import { MAX_ADVICE_STATE_BYTES } from "./recipe-assistance-rubric.js";
|
|
12
9
|
function digest(value) {
|
|
13
10
|
return createHash("sha256").update(value).digest("hex");
|
|
@@ -48,7 +45,7 @@ async function buildAdviceContext(input) {
|
|
|
48
45
|
const task = readInput(input.task);
|
|
49
46
|
if (!input.recipe) throw new CliError("Advice requires a recipe. Next: use recipe-quality plan before authoring.", EXIT.usage);
|
|
50
47
|
readInput(input.recipe);
|
|
51
|
-
const validated = await validateRunRecipeStatic(input.recipe, input.adapter, input.options ?? {}, input.params);
|
|
48
|
+
const validated = await validateRunRecipeStatic(metaMaskEngine, input.recipe, input.adapter, input.options ?? {}, input.params);
|
|
52
49
|
if (validated.usageError || !validated.schemaValid || !isRecord(validated.recipe)) {
|
|
53
50
|
const detail = validated.usageError?.message ?? validated.findings.map((finding) => finding.message).join("; ");
|
|
54
51
|
throw new CliError(`Recipe is not statically valid: ${detail}. Next: run mm-harness run ${input.recipe} --plan --adapter ${input.adapter}.`, EXIT.validation);
|
|
@@ -58,7 +55,7 @@ async function buildAdviceContext(input) {
|
|
|
58
55
|
const dependencies = resolveRecipeDependencies({ rootRef: rootResolutionRef(rootDigest), root: validated.recipe, rootSource: { kind: "recipe-file", trust: "unknown", digest: rootDigest }, recipes: library.recipes });
|
|
59
56
|
const composition = recipeComposition(validated.recipe, dependencies.recipes);
|
|
60
57
|
const { manifest, actionSources } = await resolveActionManifest(input.adapter, void 0, validated.librarySources);
|
|
61
|
-
const catalog = describeManifestActions(manifest, actionSources);
|
|
58
|
+
const catalog = describeManifestActions(metaMaskEngine, manifest, actionSources);
|
|
62
59
|
const used = new Set(composition.actions);
|
|
63
60
|
const actions = catalog.filter((action) => used.has(action.name)).map(({ name, description, schema, capabilities }) => ({ name, description, schema, capabilities }));
|
|
64
61
|
const domains = new Set(composition.actions.map((name) => name.split(".").slice(0, -1).join(".")));
|
|
@@ -110,12 +107,12 @@ async function buildPlanningContext(input) {
|
|
|
110
107
|
throw new CliError("Planning requires 1\u201320 non-empty acceptanceCriteria strings. Next: supply a focused JSON task.", EXIT.validation);
|
|
111
108
|
}
|
|
112
109
|
const criteria = task.acceptanceCriteria;
|
|
113
|
-
const sources = await
|
|
110
|
+
const sources = await resolveLibrarySources(metaMaskEngine, optionStrings(input.options ?? {}, "library"));
|
|
114
111
|
const library = await loadRecipeLibraries(sources ?? [], { adapter: input.adapter });
|
|
115
112
|
const { manifest, actionSources } = await resolveActionManifest(input.adapter, void 0, sources);
|
|
116
113
|
const candidates = [
|
|
117
114
|
...[...library.recipes.values()].map((recipe) => ({ id: `recipe:${recipe.ref}`, kind: "recipe", ref: recipe.ref, description: typeof recipe.document.description === "string" ? recipe.document.description : "", parameters: recipe.document.paramsSchema, source: recipe.source, provenance: recipe.provenance, shadows: recipe.shadows })),
|
|
118
|
-
...describeManifestActions(manifest, actionSources).map((action) => ({ id: `action:${action.name}`, kind: "action", ref: action.name, description: action.description, parameters: action.schema, capabilities: action.capabilities, source: action.source, sourceTier: action.sourceTier, shadows: action.shadows }))
|
|
115
|
+
...describeManifestActions(metaMaskEngine, manifest, actionSources).map((action) => ({ id: `action:${action.name}`, kind: "action", ref: action.name, description: action.description, parameters: action.schema, capabilities: action.capabilities, source: action.source, sourceTier: action.sourceTier, shadows: action.shadows }))
|
|
119
116
|
];
|
|
120
117
|
const terms = new Set(criteria.join(" ").toLowerCase().match(/[a-z][a-z_]{3,}/gu) ?? []);
|
|
121
118
|
const score = (candidate) => [...new Set(`${candidate.ref} ${candidate.description}`.toLowerCase().match(/[a-z][a-z_]{3,}/gu) ?? [])].filter((word) => terms.has(word)).length;
|