@deeeed/metamask-harness 0.5.1 → 0.6.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +37 -20
  2. package/adapters/core/inject.sh +1 -0
  3. package/adapters/extension/cleanup.mjs +1 -1
  4. package/adapters/extension/inject.mjs +2 -1
  5. package/adapters/extension/launch-browser.cjs +18 -4
  6. package/adapters/extension/live.sh +14 -2
  7. package/adapters/extension/sidepanel-toggle.sh +33 -12
  8. package/adapters/extension/wallet-fixture-state.cjs +38 -24
  9. package/adapters/manifest.json +13 -0
  10. package/adapters/mobile/inject.sh +1 -0
  11. package/adapters/mobile/stop-metro.sh +20 -0
  12. package/adapters/shared/cli-ux.sh +20 -2
  13. package/adapters/shared/ensure-runner-deps.sh +30 -0
  14. package/adapters/shared/reap-checkout-metros.sh +53 -0
  15. package/adapters/shared/recipe-harness-root.mjs +23 -0
  16. package/adapters/shared/resolve-farmslot-ports-core.mjs +15 -6
  17. package/bin/mm-harness +45 -4
  18. package/dist/adapters/extension/runtime.js +3 -1
  19. package/dist/adapters/mobile/provision.js +34 -1
  20. package/dist/adapters/slot-ports.js +3 -8
  21. package/dist/cli.js +32 -1463
  22. package/dist/commands/call.js +183 -0
  23. package/dist/commands/completion-candidates.js +58 -0
  24. package/dist/commands/doctor.js +101 -0
  25. package/dist/commands/ensure-ready.js +24 -0
  26. package/dist/commands/flows.js +62 -0
  27. package/dist/commands/launch/extension.js +40 -0
  28. package/dist/commands/{launch.js → launch/index.js} +15 -47
  29. package/dist/commands/launch/mobile.js +10 -0
  30. package/dist/commands/manifest.js +72 -0
  31. package/dist/commands/parse-args.js +189 -0
  32. package/dist/commands/provision.js +136 -0
  33. package/dist/commands/resolve-extension.js +23 -0
  34. package/dist/commands/run-engine.js +341 -0
  35. package/dist/commands/run.js +217 -0
  36. package/dist/commands/runtime-decision.js +58 -0
  37. package/dist/commands/runtime-health.js +25 -0
  38. package/dist/commands/runtime-launch.js +139 -0
  39. package/dist/commands/self-test.js +52 -0
  40. package/dist/commands/stop.js +52 -0
  41. package/dist/harness.js +8 -48
  42. package/dist/mm-harness-cli.js +13 -8
  43. package/docs/CLI-SPEC.md +1 -1
  44. package/docs/CODE-MAP.md +62 -0
  45. package/library/README.md +14 -0
  46. package/library/actions/extension/platform/cdp.mjs +1 -1
  47. package/library/actions/extension/wallet/ensure_unlocked.mjs +6 -0
  48. package/library/actions/mobile/wallet/ensure_unlocked.mjs +13 -1
  49. package/package.json +6 -7
  50. package/src/adapters/core/surface.ts +0 -71
  51. package/src/adapters/extension/ensure-ready.ts +0 -185
  52. package/src/adapters/extension/extension-id.ts +0 -107
  53. package/src/adapters/extension/runtime-decision.ts +0 -445
  54. package/src/adapters/extension/runtime.ts +0 -407
  55. package/src/adapters/extension/surface.ts +0 -88
  56. package/src/adapters/mobile/deps-markers.ts +0 -21
  57. package/src/adapters/mobile/prepare.ts +0 -246
  58. package/src/adapters/mobile/provision.ts +0 -594
  59. package/src/adapters/mobile/runtime-decision.ts +0 -466
  60. package/src/adapters/mobile/surface.ts +0 -71
  61. package/src/adapters/resolve-farmslot-ports.ts +0 -13
  62. package/src/adapters/slot-ports.ts +0 -158
  63. package/src/adapters/surface.ts +0 -117
  64. package/src/adapters.ts +0 -601
  65. package/src/cli-color.ts +0 -92
  66. package/src/cli-commands.ts +0 -250
  67. package/src/cli-version.ts +0 -141
  68. package/src/cli.ts +0 -2091
  69. package/src/commands/debug.ts +0 -65
  70. package/src/commands/fixtures.ts +0 -198
  71. package/src/commands/launch.ts +0 -470
  72. package/src/commands/logs.ts +0 -99
  73. package/src/commands/shared.ts +0 -235
  74. package/src/commands/update.ts +0 -316
  75. package/src/completions-cache.ts +0 -86
  76. package/src/doctor.ts +0 -215
  77. package/src/harness.ts +0 -797
  78. package/src/heal-bounds.ts +0 -198
  79. package/src/index.ts +0 -15
  80. package/src/leaf-invoke.ts +0 -28
  81. package/src/live-adapter-contract.ts +0 -274
  82. package/src/manifest.ts +0 -47
  83. package/src/mm-harness-cli.ts +0 -655
  84. package/src/paths.ts +0 -198
  85. package/src/progress.ts +0 -117
  86. package/src/recording-target.ts +0 -147
  87. package/src/run-recording.ts +0 -329
  88. package/src/runner.ts +0 -108
  89. package/src/types.ts +0 -57
@@ -1,65 +0,0 @@
1
- // debug — open the debug console by composing open-debug.mjs directly:
2
- // extension `debug` (--worker → service-worker target); mobile `debug`
3
- // (--dev-menu → developer menu). Cross-platform flag misuse teaches (exit 2).
4
-
5
- import path from 'node:path';
6
-
7
- import { runnerDir } from '../paths.ts';
8
- import { getAdapterSurface } from '../adapters/surface.ts';
9
- import { ADAPTER_DETECT_NEXT, EXIT, flag, parseFlags, resolveAdapter, spawnScript, targetOf, usageOut } from './shared.ts';
10
-
11
- const DEBUG_BOOLEANS = new Set(['worker', 'devMenu', 'json']);
12
-
13
- export async function handleDebug(argv: string[]): Promise<number> {
14
- const { options } = parseFlags(argv, DEBUG_BOOLEANS);
15
- const json = flag(options, 'json');
16
- const target = targetOf(options);
17
- const adapter = resolveAdapter(options, target);
18
-
19
- if (!adapter) return usageOut(json, 'debug', `could not detect the MetaMask repo type for ${target}`, ADAPTER_DETECT_NEXT);
20
- const surface = getAdapterSurface(adapter);
21
- if (surface.headless) return usageOut(json, 'debug', 'core is headless; there is no debug console.', surface.hints.relaunch);
22
-
23
- const worker = flag(options, 'worker');
24
- const devMenu = flag(options, 'devMenu');
25
- if (adapter === 'mobile' && worker) {
26
- return usageOut(
27
- json,
28
- 'debug',
29
- '--worker is extension-only (service-worker DevTools). Use --dev-menu on mobile.',
30
- 'mm-harness debug --dev-menu',
31
- );
32
- }
33
- if (adapter === 'extension' && devMenu) {
34
- return usageOut(
35
- json,
36
- 'debug',
37
- '--dev-menu is mobile-only (RN developer menu). Use --worker on the extension.',
38
- 'mm-harness debug --worker',
39
- );
40
- }
41
-
42
- const openDebug = path.join(runnerDir, 'adapters/shared/open-debug.mjs');
43
- const debugArgs: string[] = ['--adapter', adapter];
44
-
45
- if (adapter === 'extension') {
46
- if (process.env.CDP_PORT) debugArgs.push('--cdp-port', process.env.CDP_PORT);
47
- debugArgs.push('--target', worker ? 'worker' : 'page');
48
- } else {
49
- if (process.env.WATCHER_PORT) debugArgs.push('--port', process.env.WATCHER_PORT);
50
- debugArgs.push('--action', devMenu ? 'dev-menu' : 'debug');
51
- }
52
- if (json) debugArgs.push('--json');
53
-
54
- const result = spawnScript(process.execPath, [openDebug, ...debugArgs], target, json);
55
- if (json) {
56
- console.log(
57
- JSON.stringify(
58
- { schemaVersion: 1, command: 'debug', adapter, mode: worker ? 'worker' : devMenu ? 'dev-menu' : 'default', exitCode: result.status === 0 ? EXIT.ok : EXIT.runtime },
59
- null,
60
- 2,
61
- ),
62
- );
63
- }
64
- return result.status === 0 ? EXIT.ok : EXIT.runtime;
65
- }
@@ -1,198 +0,0 @@
1
- // fixtures <sync|set> — manage wallet DATA (never overlay/runtime state). `sync`
2
- // re-renders the wallet fixture files; `set` applies THE canonical fixture (SRP/
3
- // password read FROM the fixture, never typed) and always teaches the edit path.
4
-
5
- import fs from 'node:fs';
6
- import path from 'node:path';
7
-
8
- import { runnerDir, walletFixturePath } from '../paths.ts';
9
- import { getAdapterSurface } from '../adapters/surface.ts';
10
- import type { MetaMaskRecipeAdapter } from '../types.ts';
11
- import { ADAPTER_DETECT_NEXT, EXIT, flag, parseFlags, resolveAdapter, spawnScript, str, targetOf, usageOut } from './shared.ts';
12
-
13
- // One node injected from cli.ts so `fixtures set` can reuse the real engine path
14
- // (`call`'s one-node machinery) without a circular import.
15
- export interface CommandDeps {
16
- runOneNode: (
17
- adapter: MetaMaskRecipeAdapter,
18
- action: string,
19
- args: Record<string, string>,
20
- target: string,
21
- actionManifest: string | undefined,
22
- ) => Promise<{ status: 'pass' | 'fail' }>;
23
- }
24
-
25
- const FIXTURES_BOOLEANS = new Set(['json']);
26
-
27
- // Patterns indicating setup-wallet failed due to a Metro/bridge issue (not a bad
28
- // fixture). A clean Metro restart + relaunch is likely to resolve these.
29
- // Mirrors baseline mm-recipe:820-824 setup_wallet_failure_recoverable patterns.
30
- const RECOVERABLE_SETUP_WALLET_PATTERNS = [
31
- 'CDP not reachable',
32
- 'CDP bridge',
33
- 'is not installed',
34
- 'Engine.context.KeyringController not available',
35
- 'Engine does not exist',
36
- "Cannot read property 'transactions'",
37
- 'bridge-not-ready',
38
- 'debug-target-missing',
39
- 'CDP eval failed',
40
- 'CDP eval-async failed',
41
- ];
42
-
43
- function isRecoverableSetupWalletFailure(output: string): boolean {
44
- return RECOVERABLE_SETUP_WALLET_PATTERNS.some((p) => output.includes(p));
45
- }
46
-
47
- export async function handleFixtures(argv: string[], deps: CommandDeps): Promise<number> {
48
- const { positional, options } = parseFlags(argv, FIXTURES_BOOLEANS);
49
- const json = flag(options, 'json');
50
- const sub = positional[0];
51
- if (sub !== 'sync' && sub !== 'set') {
52
- return usageOut(json, 'fixtures', 'fixtures requires a subcommand: mm-harness fixtures <sync|set>', 'mm-harness fixtures sync or mm-harness fixtures set');
53
- }
54
- const target = targetOf(options);
55
- const adapter = resolveAdapter(options, target);
56
- if (!adapter) {
57
- return usageOut(json, 'fixtures', `could not detect the MetaMask repo type for ${target}`, ADAPTER_DETECT_NEXT);
58
- }
59
- const surface = getAdapterSurface(adapter);
60
- if (surface.headless) return usageOut(json, 'fixtures', 'core is headless; it has no wallet fixture.', surface.hints.launch);
61
-
62
- const canonicalFixture = walletFixturePath(target);
63
- // Platform-phrased retry hint on a setup-wallet failure: the surface owns the
64
- // (re)build/relaunch command; this command never spells out another platform's.
65
- const retryHint = `${surface.hints.relaunch} # relaunch, then retry: mm-harness fixtures set`;
66
-
67
- if (sub === 'sync') {
68
- const exitCode = fixturesSync(adapter, target, json);
69
- if (json) {
70
- console.log(
71
- JSON.stringify(
72
- { schemaVersion: 1, command: 'fixtures', action: 'sync', adapter, fixture: canonicalFixture, exitCode },
73
- null,
74
- 2,
75
- ),
76
- );
77
- }
78
- return exitCode;
79
- }
80
-
81
- // set — apply THE canonical wallet fixture (password read FROM the fixture).
82
- // Env-gap resolution (docs/CLI-SPEC.md Part 4): flag > env RECIPE_WALLET_FIXTURE
83
- // > the slot's canonical fixture.
84
- const fixturePath = path.resolve(str(options, 'fixture') ?? process.env.RECIPE_WALLET_FIXTURE ?? canonicalFixture);
85
- let status: 'pass' | 'fail';
86
- if (adapter === 'mobile') {
87
- // Compose setup-wallet.sh directly (requires bridge to be live).
88
- const setupWalletSh = path.join(runnerDir, 'adapters/mobile/bridge-runtime/setup-wallet.sh');
89
- const previousAppRoot = process.env.APP_ROOT;
90
- process.env.APP_ROOT = target;
91
- try {
92
- let result = spawnScript(setupWalletSh, ['--fixture', fixturePath], target, json);
93
- // One clean-Metro auto-retry on recoverable failures (CDP unreachable, bridge
94
- // not installed). RECIPE_SETUP_WALLET_RETRIED guards against infinite loops.
95
- if (result.status !== 0 && isRecoverableSetupWalletFailure(result.output) && !process.env['RECIPE_SETUP_WALLET_RETRIED']) {
96
- process.env['RECIPE_SETUP_WALLET_RETRIED'] = '1';
97
- if (!json) process.stderr.write(' setup-wallet: recoverable failure — restarting Metro and retrying\n Next: wait for relaunch, then wallet setup will retry automatically\n');
98
- const { prepareMobile } = await import('../adapters/mobile/prepare.ts');
99
- const platform = str(options, 'platform') ?? process.env['MOBILE_PLATFORM'] ?? 'ios';
100
- const relaunchResult = await prepareMobile(target, { platform, json, preflightMode: 'auto', clearMetro: true });
101
- if (relaunchResult.status === 0) {
102
- result = spawnScript(setupWalletSh, ['--fixture', fixturePath], target, json);
103
- }
104
- }
105
- status = result.status === 0 ? 'pass' : 'fail';
106
- } finally {
107
- delete process.env['RECIPE_SETUP_WALLET_RETRIED'];
108
- if (previousAppRoot === undefined) delete process.env.APP_ROOT;
109
- else process.env.APP_ROOT = previousAppRoot;
110
- }
111
- if (!json && status === 'fail') {
112
- console.error(` Next: ${retryHint}`);
113
- }
114
- } else {
115
- // Extension has no standalone set arm — reuse call's one-node machinery via
116
- // the real engine path (metamask.wallet.setup in the manifest).
117
- if (!fs.existsSync(fixturePath)) {
118
- return usageOut(
119
- json,
120
- 'fixtures',
121
- `no wallet fixture at ${fixturePath}.`,
122
- 'create it (or pass --fixture <path>), then re-run: mm-harness fixtures set',
123
- );
124
- }
125
- const previousFixtureEnv = process.env.RECIPE_WALLET_FIXTURE;
126
- process.env.RECIPE_WALLET_FIXTURE = fixturePath;
127
- try {
128
- const result = await deps.runOneNode('extension', 'metamask.wallet.setup', {}, target, str(options, 'actionManifest'));
129
- status = result.status;
130
- } finally {
131
- if (previousFixtureEnv === undefined) delete process.env.RECIPE_WALLET_FIXTURE;
132
- else process.env.RECIPE_WALLET_FIXTURE = previousFixtureEnv;
133
- }
134
- if (!json && status === 'fail') {
135
- console.error(` Next: ${retryHint}`);
136
- }
137
- }
138
-
139
- // Always teach where to customize the wallet.
140
- const teaching = `Wallet fixture applied. Want different accounts? Edit: ${canonicalFixture}`;
141
- if (json) {
142
- console.log(
143
- JSON.stringify(
144
- {
145
- schemaVersion: 1,
146
- command: 'fixtures',
147
- action: 'set',
148
- adapter,
149
- fixture: fixturePath,
150
- canonicalFixture,
151
- status,
152
- exitCode: status === 'pass' ? EXIT.ok : EXIT.runtime,
153
- message: teaching,
154
- error: status === 'fail' ? {
155
- code: 'SETUP_WALLET_FAILED',
156
- message: 'wallet fixture setup failed',
157
- userAction: retryHint,
158
- } : null,
159
- },
160
- null,
161
- 2,
162
- ),
163
- );
164
- } else {
165
- console.error(teaching);
166
- }
167
- return status === 'pass' ? EXIT.ok : EXIT.runtime;
168
- }
169
-
170
- // Sync the overlay installation + wallet fixture for the checkout.
171
- // Re-runs the adapter inject to refresh patched files, then copies the wallet
172
- // fixture to the canonical runtime location via sync-wallet-fixture.sh. Reached
173
- // only for device adapters (headless core returns earlier); the adapter is
174
- // forwarded verbatim to `install`.
175
- function fixturesSync(adapter: MetaMaskRecipeAdapter, target: string, json: boolean): number {
176
- const mmHarnessBin = path.join(runnerDir, 'bin/mm-harness');
177
- const installResult = spawnScript(
178
- mmHarnessBin,
179
- ['install', '--adapter', adapter, '--target', target],
180
- target,
181
- json,
182
- );
183
- if (installResult.status !== 0) {
184
- if (!json) {
185
- console.error(`✗ mm-harness fixtures sync: overlay reinstall failed.\n Next: mm-harness install --target ${target} # diagnose the install failure`);
186
- }
187
- return EXIT.runtime;
188
- }
189
-
190
- const syncFixtureSh = path.join(runnerDir, 'adapters/shared/sync-wallet-fixture.sh');
191
- const syncArgs = ['--target', target];
192
- if (process.env.CDP_PORT) syncArgs.push('--cdp-port', process.env.CDP_PORT);
193
- if (process.env.RECIPE_SLOT_ID) syncArgs.push('--slot-id', process.env.RECIPE_SLOT_ID);
194
- spawnScript(syncFixtureSh, syncArgs, target, json);
195
- // Non-zero from sync-wallet-fixture.sh is informational (no fixture source);
196
- // the install succeeded so the overlay is fresh.
197
- return EXIT.ok;
198
- }