@deeeed/metamask-harness 0.5.0 → 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 (102) hide show
  1. package/CHANGELOG.md +51 -20
  2. package/adapters/core/inject.sh +1 -0
  3. package/adapters/extension/cleanup.mjs +1 -1
  4. package/adapters/extension/inject.mjs +4 -1
  5. package/adapters/extension/launch-browser.cjs +18 -4
  6. package/adapters/extension/live.sh +14 -2
  7. package/adapters/extension/refresh-build.sh +2 -2
  8. package/adapters/extension/sidepanel-toggle.sh +33 -12
  9. package/adapters/extension/start-watch.sh +2 -2
  10. package/adapters/extension/wallet-fixture-state.cjs +38 -24
  11. package/adapters/manifest.json +32 -3
  12. package/adapters/mobile/inject.sh +1 -0
  13. package/adapters/mobile/start-metro.sh +1 -1
  14. package/adapters/mobile/stop-metro.sh +20 -0
  15. package/adapters/mobile/verify.sh +1 -1
  16. package/adapters/shared/activate-repo-node.sh +1 -1
  17. package/adapters/shared/cli-ux.sh +44 -25
  18. package/adapters/shared/ensure-runner-deps.sh +30 -0
  19. package/adapters/shared/log-tui.mjs +4 -4
  20. package/adapters/shared/open-debug.mjs +1 -1
  21. package/adapters/shared/reap-checkout-metros.sh +53 -0
  22. package/adapters/shared/recipe-harness-root.mjs +23 -0
  23. package/adapters/shared/resolve-farmslot-ports-core.mjs +205 -0
  24. package/adapters/shared/resolve-farmslot-ports.mjs +20 -0
  25. package/adapters/shared/resolve-farmslot-ports.sh +19 -126
  26. package/bin/mm-harness +45 -4
  27. package/dist/adapters/extension/runtime.js +3 -1
  28. package/dist/adapters/mobile/provision.js +34 -1
  29. package/dist/adapters/mobile/runtime-decision.js +3 -1
  30. package/dist/adapters/resolve-farmslot-ports.js +22 -0
  31. package/dist/adapters/slot-ports.js +18 -29
  32. package/dist/cli.js +32 -1463
  33. package/dist/commands/call.js +183 -0
  34. package/dist/commands/completion-candidates.js +58 -0
  35. package/dist/commands/doctor.js +101 -0
  36. package/dist/commands/ensure-ready.js +24 -0
  37. package/dist/commands/flows.js +62 -0
  38. package/dist/commands/launch/extension.js +40 -0
  39. package/dist/commands/{launch.js → launch/index.js} +15 -47
  40. package/dist/commands/launch/mobile.js +10 -0
  41. package/dist/commands/manifest.js +72 -0
  42. package/dist/commands/parse-args.js +189 -0
  43. package/dist/commands/provision.js +136 -0
  44. package/dist/commands/resolve-extension.js +23 -0
  45. package/dist/commands/run-engine.js +341 -0
  46. package/dist/commands/run.js +217 -0
  47. package/dist/commands/runtime-decision.js +58 -0
  48. package/dist/commands/runtime-health.js +25 -0
  49. package/dist/commands/runtime-launch.js +139 -0
  50. package/dist/commands/self-test.js +52 -0
  51. package/dist/commands/stop.js +52 -0
  52. package/dist/harness.js +8 -48
  53. package/dist/mm-harness-cli.js +13 -8
  54. package/docs/CLI-SPEC.md +1 -1
  55. package/docs/CODE-MAP.md +62 -0
  56. package/library/README.md +14 -0
  57. package/library/actions/core/perps/_controller.mjs +1 -1
  58. package/library/actions/extension/platform/cdp.mjs +2 -2
  59. package/library/actions/extension/wallet/ensure_unlocked.mjs +7 -1
  60. package/library/actions/harness-exports.mjs +27 -0
  61. package/library/actions/mobile/wallet/ensure_unlocked.mjs +14 -2
  62. package/library/actions/mobile/wallet/setup.mjs +1 -1
  63. package/package.json +6 -7
  64. package/src/adapters/core/surface.ts +0 -71
  65. package/src/adapters/extension/ensure-ready.ts +0 -185
  66. package/src/adapters/extension/extension-id.ts +0 -107
  67. package/src/adapters/extension/runtime-decision.ts +0 -445
  68. package/src/adapters/extension/runtime.ts +0 -407
  69. package/src/adapters/extension/surface.ts +0 -88
  70. package/src/adapters/mobile/deps-markers.ts +0 -21
  71. package/src/adapters/mobile/prepare.ts +0 -246
  72. package/src/adapters/mobile/provision.ts +0 -594
  73. package/src/adapters/mobile/runtime-decision.ts +0 -459
  74. package/src/adapters/mobile/surface.ts +0 -71
  75. package/src/adapters/slot-ports.ts +0 -165
  76. package/src/adapters/surface.ts +0 -117
  77. package/src/adapters.ts +0 -601
  78. package/src/cli-color.ts +0 -92
  79. package/src/cli-commands.ts +0 -250
  80. package/src/cli-version.ts +0 -141
  81. package/src/cli.ts +0 -2091
  82. package/src/commands/debug.ts +0 -65
  83. package/src/commands/fixtures.ts +0 -198
  84. package/src/commands/launch.ts +0 -470
  85. package/src/commands/logs.ts +0 -99
  86. package/src/commands/shared.ts +0 -235
  87. package/src/commands/update.ts +0 -316
  88. package/src/completions-cache.ts +0 -86
  89. package/src/doctor.ts +0 -215
  90. package/src/harness.ts +0 -797
  91. package/src/heal-bounds.ts +0 -198
  92. package/src/index.ts +0 -15
  93. package/src/leaf-invoke.ts +0 -28
  94. package/src/live-adapter-contract.ts +0 -274
  95. package/src/manifest.ts +0 -47
  96. package/src/mm-harness-cli.ts +0 -655
  97. package/src/paths.ts +0 -198
  98. package/src/progress.ts +0 -117
  99. package/src/recording-target.ts +0 -147
  100. package/src/run-recording.ts +0 -329
  101. package/src/runner.ts +0 -108
  102. 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
- }