@deeeed/metamask-harness 0.11.0 → 0.13.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 +24 -0
- package/adapters/core/cleanup.sh +0 -0
- package/adapters/core/inject.sh +0 -0
- package/adapters/extension/cleanup.mjs +0 -0
- package/adapters/extension/ensure-browser.sh +0 -0
- package/adapters/extension/inject.mjs +0 -0
- package/adapters/extension/launch-browser.cjs +0 -0
- package/adapters/extension/launch.sh +0 -0
- package/adapters/extension/live.sh +0 -0
- package/adapters/extension/readiness.mjs +0 -0
- package/adapters/extension/reattach.sh +0 -0
- package/adapters/extension/refresh-build.sh +0 -0
- package/adapters/extension/seed-fixture.sh +0 -0
- package/adapters/extension/sidepanel-toggle.sh +0 -0
- package/adapters/extension/snapshot-dist.sh +0 -0
- package/adapters/extension/start-watch.sh +0 -0
- package/adapters/extension/verify.sh +0 -0
- package/adapters/extension/wallet-fixture-state.cjs +0 -0
- package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +63 -0
- package/adapters/mobile/bridge-runtime/console-forwarder.cjs +341 -0
- package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +106 -0
- package/adapters/mobile/bridge-runtime/lib/console-format.cjs +53 -0
- package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +82 -0
- package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +48 -42
- package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +10 -5
- package/adapters/mobile/bridge-runtime/setup-wallet.sh +0 -0
- package/adapters/mobile/cleanup.sh +4 -0
- package/adapters/mobile/inject.sh +0 -0
- package/adapters/mobile/lib/metro-listener.sh +0 -0
- package/adapters/mobile/lib/tmux-viewer.sh +0 -0
- package/adapters/mobile/open-device.sh +0 -0
- package/adapters/mobile/prewarm-bundle.sh +0 -0
- package/adapters/mobile/start-metro.sh +37 -0
- package/adapters/mobile/stop-metro.sh +21 -0
- package/adapters/mobile/verify.sh +0 -0
- package/adapters/mobile/wait-for-bridge.sh +41 -23
- package/adapters/mobile/yarn-setup.sh +0 -0
- package/adapters/shared/activate-repo-node.sh +0 -0
- package/adapters/shared/activate-repo-ruby.sh +0 -0
- package/adapters/shared/cli-ux.sh +0 -0
- package/adapters/shared/ensure-runner-deps.sh +0 -0
- package/adapters/shared/harness-path.sh +0 -0
- package/adapters/shared/hash-helpers.sh +0 -0
- package/adapters/shared/json-field.sh +0 -0
- package/adapters/shared/open-debug.mjs +5 -0
- package/adapters/shared/open-log-window.sh +0 -0
- package/adapters/shared/reap-checkout-metros.sh +0 -0
- package/adapters/shared/resolve-farmslot-ports.mjs +0 -0
- package/adapters/shared/resolve-farmslot-ports.sh +0 -0
- package/adapters/shared/resolve-slot-ports.mjs +0 -0
- package/adapters/shared/resolve-slot-ports.sh +0 -0
- package/adapters/shared/sync-wallet-fixture.sh +0 -0
- package/adapters/shared/tmux-session.sh +0 -0
- package/dist/adapters/mobile/prepare.js +23 -2
- package/dist/adapters/mobile/runtime-decision.js +2 -1
- package/dist/adapters.js +39 -9
- package/dist/commands/call.js +80 -1
- package/dist/commands/manifest.js +2 -0
- package/dist/commands/run-engine.js +9 -1
- package/dist/mm-harness-cli.js +12 -0
- package/dist/runner.js +2 -2
- package/library/actions/mobile/platform/bridge.mjs +35 -4
- package/package.json +2 -2
- package/scripts/completions.sh +0 -0
- package/scripts/install-completions.sh +0 -0
package/dist/adapters.js
CHANGED
|
@@ -2,7 +2,7 @@ import http from "node:http";
|
|
|
2
2
|
import { compatibilityMode, fixtureSummary, repoShape } from "./doctor.js";
|
|
3
3
|
import { runLiveAdapterScript } from "./live-adapter-contract.js";
|
|
4
4
|
import { withExtensionPage } from "../library/actions/extension/platform/cdp.mjs";
|
|
5
|
-
import { bridgeCommand, evalSync, selectBridgeStatusEntry, simulatorScreenshot } from "../library/actions/mobile/platform/bridge.mjs";
|
|
5
|
+
import { bridgeCommand, evalSync, MOBILE_BRIDGE_ERROR_CODES, selectBridgeStatusEntry, simulatorScreenshot } from "../library/actions/mobile/platform/bridge.mjs";
|
|
6
6
|
function sleep(ms) {
|
|
7
7
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
8
|
}
|
|
@@ -331,9 +331,23 @@ async function handleMobileHud(payload, context) {
|
|
|
331
331
|
return mobileHudSkippedOrThrow(error, { nodeId: hud.nodeId, status: hud.status });
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
|
+
async function hideMobileHudOnTeardown(projectRoot, env = {}) {
|
|
335
|
+
if (process.env.METAMASK_RECIPE_AUTO_HUD === "0" || process.env.METAMASK_RECIPE_AUTO_HUD === "false") return;
|
|
336
|
+
const input = {
|
|
337
|
+
node: { bridge_timeout_ms: 8e3, cdp_timeout_ms: 5e3 },
|
|
338
|
+
context: { nodeId: "teardown", projectRoot, artifactsDir: projectRoot, env }
|
|
339
|
+
};
|
|
340
|
+
try {
|
|
341
|
+
await bridgeCommand(input, ["hide-step"]);
|
|
342
|
+
} catch {
|
|
343
|
+
}
|
|
344
|
+
}
|
|
334
345
|
function mobileHudSkippedOrThrow(error, extra = {}) {
|
|
335
346
|
const reason = traceText(error);
|
|
336
|
-
|
|
347
|
+
const code = isRecord(error) && typeof error.code === "string" ? error.code : void 0;
|
|
348
|
+
if (isMobileHudLifecycleSkip(reason, code)) {
|
|
349
|
+
process.stderr.write(`app.hud skipped (bridge target down or transitioning): ${reason}
|
|
350
|
+
`);
|
|
337
351
|
return {
|
|
338
352
|
hud: false,
|
|
339
353
|
skipped: true,
|
|
@@ -344,16 +358,30 @@ function mobileHudSkippedOrThrow(error, extra = {}) {
|
|
|
344
358
|
}
|
|
345
359
|
throw new Error(`app.hud bridge command failed outside a lifecycle/no-target transition: ${reason}`);
|
|
346
360
|
}
|
|
347
|
-
|
|
361
|
+
const HUD_LIFECYCLE_SKIP_CODES = /* @__PURE__ */ new Set([
|
|
362
|
+
MOBILE_BRIDGE_ERROR_CODES.NO_TARGET,
|
|
363
|
+
MOBILE_BRIDGE_ERROR_CODES.CDP_TIMEOUT,
|
|
364
|
+
MOBILE_BRIDGE_ERROR_CODES.WS_CLOSED,
|
|
365
|
+
MOBILE_BRIDGE_ERROR_CODES.METRO_UNREACHABLE
|
|
366
|
+
]);
|
|
367
|
+
function isMobileHudLifecycleSkip(reason, code) {
|
|
368
|
+
if (code && HUD_LIFECYCLE_SKIP_CODES.has(code)) return true;
|
|
369
|
+
const haystack = reason.toLowerCase();
|
|
348
370
|
return [
|
|
349
371
|
"no responding bridge target",
|
|
350
|
-
"
|
|
372
|
+
"pinned android device",
|
|
351
373
|
"bridge probe failed",
|
|
352
|
-
"
|
|
374
|
+
"econnrefused",
|
|
353
375
|
"timed out",
|
|
354
|
-
"
|
|
355
|
-
|
|
356
|
-
|
|
376
|
+
"no react native bridge target",
|
|
377
|
+
// Metro down mid-run: HUD cannot paint, so skip rather than abort (the real
|
|
378
|
+
// action fails on its own). Matches the METRO_UNREACHABLE code branch above.
|
|
379
|
+
"cannot reach metro",
|
|
380
|
+
// Dev-client foreground/reload kills the Hermes page mid-flight: pending
|
|
381
|
+
// CDP calls surface as a message timeout or a closed socket.
|
|
382
|
+
"cdp message timeout",
|
|
383
|
+
"websocket closed"
|
|
384
|
+
].some((needle) => haystack.includes(needle));
|
|
357
385
|
}
|
|
358
386
|
function animatedFlag(payload) {
|
|
359
387
|
return payload.animated === true ? "--animated" : "--no-animated";
|
|
@@ -504,5 +532,7 @@ function targetProbeUrl(platform, targetPort) {
|
|
|
504
532
|
}
|
|
505
533
|
export {
|
|
506
534
|
createMetaMaskAdapters,
|
|
507
|
-
createMetaMaskUiTransport
|
|
535
|
+
createMetaMaskUiTransport,
|
|
536
|
+
hideMobileHudOnTeardown,
|
|
537
|
+
isMobileHudLifecycleSkip
|
|
508
538
|
};
|
package/dist/commands/call.js
CHANGED
|
@@ -6,8 +6,10 @@ import { loadActionManifest } from "../manifest.js";
|
|
|
6
6
|
import { importRecipeProtocol } from "../paths.js";
|
|
7
7
|
import { recipeRunning } from "../heal-bounds.js";
|
|
8
8
|
import { EXIT } from "./shared.js";
|
|
9
|
+
import { describeManifestActions, fuzzyResolveActions } from "./manifest.js";
|
|
9
10
|
import {
|
|
10
11
|
parseArgs,
|
|
12
|
+
isRecord,
|
|
11
13
|
optionFlag,
|
|
12
14
|
optionString,
|
|
13
15
|
resolveAdapter,
|
|
@@ -153,6 +155,82 @@ Artifacts: ${result.artifactManifestPath}`);
|
|
|
153
155
|
}
|
|
154
156
|
return result.status === "pass" ? EXIT.ok : EXIT.runtime;
|
|
155
157
|
}
|
|
158
|
+
async function handleCallHelp(argv, genericHelp) {
|
|
159
|
+
const { action: shortName, rest } = parseCallArgs(argv.filter((arg) => arg !== "--help" && arg !== "-h"));
|
|
160
|
+
const { options } = parseArgs(rest, "call");
|
|
161
|
+
let adapter;
|
|
162
|
+
let manifest;
|
|
163
|
+
try {
|
|
164
|
+
({ adapter } = resolveAdapter(options));
|
|
165
|
+
manifest = loadActionManifest(adapter, optionString(options, "actionManifest"));
|
|
166
|
+
} catch {
|
|
167
|
+
process.stdout.write(`${genericHelp}
|
|
168
|
+
`);
|
|
169
|
+
return EXIT.ok;
|
|
170
|
+
}
|
|
171
|
+
const matches = shortName ? fuzzyResolveActions(describeManifestActions(manifest), shortName) : [];
|
|
172
|
+
if (matches.length === 0) {
|
|
173
|
+
process.stdout.write(`${genericHelp}
|
|
174
|
+
`);
|
|
175
|
+
if (shortName) {
|
|
176
|
+
process.stdout.write(
|
|
177
|
+
`
|
|
178
|
+
No action matches "${shortName}" for the ${adapter} adapter.
|
|
179
|
+
Next: mm-harness actions --adapter ${adapter} # list the action vocabulary
|
|
180
|
+
`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
return EXIT.ok;
|
|
184
|
+
}
|
|
185
|
+
for (const entry of matches) process.stdout.write(renderCallActionHelp(entry));
|
|
186
|
+
process.stdout.write(`${genericHelp}
|
|
187
|
+
`);
|
|
188
|
+
return EXIT.ok;
|
|
189
|
+
}
|
|
190
|
+
function renderCallActionHelp(entry) {
|
|
191
|
+
const short = entry.name.split(".").pop() ?? entry.name;
|
|
192
|
+
const schema = isRecord(entry.schema) ? entry.schema : {};
|
|
193
|
+
const properties = isRecord(schema.properties) ? schema.properties : {};
|
|
194
|
+
const required = new Set(
|
|
195
|
+
Array.isArray(schema.required) ? schema.required.filter((r) => typeof r === "string") : []
|
|
196
|
+
);
|
|
197
|
+
const lines = [`mm-harness call ${entry.name} [--arg k=v ...] [flags]`, ""];
|
|
198
|
+
if (entry.description) lines.push(` ${entry.description}`, "");
|
|
199
|
+
const names = Object.keys(properties).sort();
|
|
200
|
+
if (names.length === 0) {
|
|
201
|
+
lines.push(" Fields: (none)");
|
|
202
|
+
} else {
|
|
203
|
+
lines.push(" Fields (pass with --arg <name>=<value>):");
|
|
204
|
+
const width = Math.max(...names.map((name) => name.length));
|
|
205
|
+
for (const name of names) {
|
|
206
|
+
const prop = isRecord(properties[name]) ? properties[name] : {};
|
|
207
|
+
const type = typeof prop.type === "string" ? prop.type : "any";
|
|
208
|
+
const req = required.has(name) ? " (required)" : "";
|
|
209
|
+
const desc = typeof prop.description === "string" ? ` \u2014 ${prop.description}` : "";
|
|
210
|
+
const enumVals = Array.isArray(prop.enum) ? ` [one of: ${prop.enum.join(", ")}]` : "";
|
|
211
|
+
lines.push(` ${name.padEnd(width)} ${type}${req}${desc}${enumVals}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const examples = renderCallExamples(short, entry.examples);
|
|
215
|
+
if (examples.length > 0) {
|
|
216
|
+
lines.push("", " Examples:");
|
|
217
|
+
for (const example of examples) lines.push(` ${example}`);
|
|
218
|
+
}
|
|
219
|
+
return `${lines.join("\n")}
|
|
220
|
+
|
|
221
|
+
`;
|
|
222
|
+
}
|
|
223
|
+
function renderCallExamples(short, examples) {
|
|
224
|
+
if (!Array.isArray(examples)) return [];
|
|
225
|
+
const out = [];
|
|
226
|
+
for (const example of examples.slice(0, 2)) {
|
|
227
|
+
const node = isRecord(example) && isRecord(example.node) ? example.node : void 0;
|
|
228
|
+
if (!node) continue;
|
|
229
|
+
const tokens = Object.entries(node).filter(([key]) => key !== "action" && key !== "intent").map(([key, value]) => `--arg ${key}=${typeof value === "string" ? value : JSON.stringify(value)}`);
|
|
230
|
+
out.push(`mm-harness call ${short} ${tokens.join(" ")}`.trim());
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
}
|
|
156
234
|
function parseCallArgs(argv) {
|
|
157
235
|
const args = {};
|
|
158
236
|
const rest = [];
|
|
@@ -191,5 +269,6 @@ function pickCallExampleAction(names) {
|
|
|
191
269
|
return names[0] ?? "command";
|
|
192
270
|
}
|
|
193
271
|
export {
|
|
194
|
-
handleCall
|
|
272
|
+
handleCall,
|
|
273
|
+
handleCallHelp
|
|
195
274
|
};
|
|
@@ -68,7 +68,15 @@ async function runRecipe(adapter, recipe, artifactsDir, projectRoot, actionManif
|
|
|
68
68
|
recordVideo: useFramedExtensionRecording ? false : recordVideo,
|
|
69
69
|
...runtimeOptions.librarySources ? { librarySources: runtimeOptions.librarySources } : {}
|
|
70
70
|
};
|
|
71
|
-
|
|
71
|
+
let result;
|
|
72
|
+
try {
|
|
73
|
+
result = await runner.run(runRequest);
|
|
74
|
+
} finally {
|
|
75
|
+
if (adapter === "mobile") {
|
|
76
|
+
const { hideMobileHudOnTeardown } = await import("../adapters.js");
|
|
77
|
+
await hideMobileHudOnTeardown(projectRoot, recipeRunEnv(adapter, runtimeOptions));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
72
80
|
await stopRecipeRecording(recording, result);
|
|
73
81
|
return result;
|
|
74
82
|
} finally {
|
package/dist/mm-harness-cli.js
CHANGED
|
@@ -5,6 +5,7 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import { color } from "./cli-color.js";
|
|
7
7
|
import { handleUpdate, maybeNudge } from "./commands/update.js";
|
|
8
|
+
import { handleCallHelp } from "./commands/call.js";
|
|
8
9
|
const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
10
|
globalThis.__MM_HARNESS_WRAPPER__ = true;
|
|
10
11
|
const { main: recipeMain } = await import("./cli.js");
|
|
@@ -614,6 +615,13 @@ function hasPassthroughHelp(argv) {
|
|
|
614
615
|
if (divider === -1) return false;
|
|
615
616
|
return argv.slice(divider + 1).some((arg) => arg === "-h" || arg === "--help");
|
|
616
617
|
}
|
|
618
|
+
function isCallActionHelp(argv) {
|
|
619
|
+
if (argv[0] !== "call") return false;
|
|
620
|
+
if (!argv[1] || argv[1].startsWith("-")) return false;
|
|
621
|
+
const divider = argv.indexOf("--");
|
|
622
|
+
const scope = divider === -1 ? argv : argv.slice(0, divider);
|
|
623
|
+
return scope.includes("--help") || scope.includes("-h");
|
|
624
|
+
}
|
|
617
625
|
if (rawArgv.length === 0) {
|
|
618
626
|
process.stdout.write(groupedHelp());
|
|
619
627
|
process.exit(0);
|
|
@@ -621,4 +629,8 @@ if (rawArgv.length === 0) {
|
|
|
621
629
|
if (hasPassthroughHelp(rawArgv)) {
|
|
622
630
|
process.exit(await delegate(rawArgv));
|
|
623
631
|
}
|
|
632
|
+
if (isCallActionHelp(rawArgv)) {
|
|
633
|
+
const callHelp = REAL.find((command) => command.name === "call")?.helpText ?? "";
|
|
634
|
+
process.exit(await handleCallHelp(rawArgv.slice(1), callHelp));
|
|
635
|
+
}
|
|
624
636
|
await program.parseAsync(process.argv);
|
package/dist/runner.js
CHANGED
|
@@ -40,10 +40,10 @@ async function createMetaMaskRunner(adapter, actionManifest, options = {}) {
|
|
|
40
40
|
})
|
|
41
41
|
});
|
|
42
42
|
const existing = new Set([...core, ...ui].map((entry) => entry.action));
|
|
43
|
-
const lifecycle =
|
|
43
|
+
const lifecycle = createAppLifecycleAdapters({
|
|
44
44
|
actions,
|
|
45
45
|
targetProvider: { resolveTarget: resolveMetaMaskMobileLifecycleTarget }
|
|
46
|
-
})
|
|
46
|
+
});
|
|
47
47
|
const custom = createMetaMaskAdapters(adapter).filter(
|
|
48
48
|
(entry) => declaredActions.has(entry.action) && !existing.has(entry.action) && !lifecycle.some((lifecycleEntry) => lifecycleEntry.action === entry.action)
|
|
49
49
|
);
|
|
@@ -3,9 +3,35 @@ import { execFile, spawn } from 'node:child_process';
|
|
|
3
3
|
import { promisify } from 'node:util';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import bridgeErrors from '../../../../adapters/mobile/bridge-runtime/lib/bridge-errors.cjs';
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
BRIDGE_ERROR_CODES,
|
|
10
|
+
ERROR_CODE_BY_EXIT_CODE,
|
|
11
|
+
classifyBridgeErrorMessage,
|
|
12
|
+
coded,
|
|
13
|
+
parseErrorMarker,
|
|
14
|
+
} = bridgeErrors;
|
|
15
|
+
|
|
16
|
+
// Re-exported so the TS adapter classifies on the same code constants without a
|
|
17
|
+
// second import path into the cjs bridge-runtime.
|
|
18
|
+
export const MOBILE_BRIDGE_ERROR_CODES = BRIDGE_ERROR_CODES;
|
|
6
19
|
|
|
7
20
|
const execFileAsync = promisify(execFile);
|
|
8
21
|
|
|
22
|
+
// Recover the typed code a cdp-bridge child reported: the stderr marker is
|
|
23
|
+
// authoritative (it carries the class the bridge classified at the source), the
|
|
24
|
+
// coded exit status is the fallback for output-less failures, and a raw message
|
|
25
|
+
// needle covers a bridge that predates the codes.
|
|
26
|
+
function bridgeChildErrorCode(exitCode, output) {
|
|
27
|
+
return (
|
|
28
|
+
parseErrorMarker(output) ||
|
|
29
|
+
ERROR_CODE_BY_EXIT_CODE[exitCode] ||
|
|
30
|
+
classifyBridgeErrorMessage(output) ||
|
|
31
|
+
null
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
9
35
|
function sleep(ms) {
|
|
10
36
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
37
|
}
|
|
@@ -169,12 +195,12 @@ export function selectBridgeStatusEntry(status, input) {
|
|
|
169
195
|
}
|
|
170
196
|
// Pinned android but no android entry answered — failing fast beats letting the
|
|
171
197
|
// caller read the iOS entry and report misleading wallet state.
|
|
172
|
-
throw new Error(
|
|
198
|
+
throw coded(new Error(
|
|
173
199
|
`Pinned android device ${adbSerial} has no responding bridge target.\n` +
|
|
174
200
|
` Bridge status entries:\n` +
|
|
175
201
|
entries.map((entry) => ` - ${entry.deviceName ?? '?'} [${entry.platform || 'unknown'}]`).join('\n') +
|
|
176
202
|
`\n Next: mm-harness launch android # bring the app back to the foreground`,
|
|
177
|
-
);
|
|
203
|
+
), BRIDGE_ERROR_CODES.NO_TARGET);
|
|
178
204
|
}
|
|
179
205
|
if (iosSimulator) {
|
|
180
206
|
const sim = entries.find((entry) => entry.deviceName === iosSimulator);
|
|
@@ -239,11 +265,16 @@ export async function bridgeCommand(input, args) {
|
|
|
239
265
|
});
|
|
240
266
|
if (result.timedOut) {
|
|
241
267
|
const command = ['node', path.relative(input.context.projectRoot, script), ...redactBridgeArgs(args)].join(' ');
|
|
242
|
-
throw
|
|
268
|
+
throw coded(
|
|
269
|
+
new Error(`Mobile CDP bridge command timed out after ${result.timeoutMs}ms: ${command}`),
|
|
270
|
+
BRIDGE_ERROR_CODES.CDP_TIMEOUT,
|
|
271
|
+
);
|
|
243
272
|
}
|
|
244
273
|
if (result.exitCode !== 0) {
|
|
245
274
|
const command = ['node', path.relative(input.context.projectRoot, script), ...redactBridgeArgs(args)].join(' ');
|
|
246
|
-
|
|
275
|
+
const code = bridgeChildErrorCode(result.exitCode, result.stderr || result.stdout);
|
|
276
|
+
const error = new Error(`Mobile CDP bridge command failed: ${command}\n${redactBridgeOutput(result.stderr || result.stdout, sensitiveBridgeArgs(args))}`);
|
|
277
|
+
throw code ? coded(error, code) : error;
|
|
247
278
|
}
|
|
248
279
|
// For transient commands, stdout of '' or 'undefined' means the state is not yet
|
|
249
280
|
// settled (e.g. mid-navigation). Return null so callers like waitForRoute can poll
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deeeed/metamask-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"mm-harness": "bin/mm-harness"
|
|
@@ -69,4 +69,4 @@
|
|
|
69
69
|
"url": "https://github.com/MetaMask/experimental-metamask-harness/issues"
|
|
70
70
|
},
|
|
71
71
|
"homepage": "https://github.com/MetaMask/experimental-metamask-harness#readme"
|
|
72
|
-
}
|
|
72
|
+
}
|
package/scripts/completions.sh
CHANGED
|
File without changes
|
|
File without changes
|