@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.
- package/CHANGELOG.md +51 -20
- package/adapters/core/inject.sh +1 -0
- package/adapters/extension/cleanup.mjs +1 -1
- package/adapters/extension/inject.mjs +4 -1
- package/adapters/extension/launch-browser.cjs +18 -4
- package/adapters/extension/live.sh +14 -2
- package/adapters/extension/refresh-build.sh +2 -2
- package/adapters/extension/sidepanel-toggle.sh +33 -12
- package/adapters/extension/start-watch.sh +2 -2
- package/adapters/extension/wallet-fixture-state.cjs +38 -24
- package/adapters/manifest.json +32 -3
- package/adapters/mobile/inject.sh +1 -0
- package/adapters/mobile/start-metro.sh +1 -1
- package/adapters/mobile/stop-metro.sh +20 -0
- package/adapters/mobile/verify.sh +1 -1
- package/adapters/shared/activate-repo-node.sh +1 -1
- package/adapters/shared/cli-ux.sh +44 -25
- package/adapters/shared/ensure-runner-deps.sh +30 -0
- package/adapters/shared/log-tui.mjs +4 -4
- package/adapters/shared/open-debug.mjs +1 -1
- package/adapters/shared/reap-checkout-metros.sh +53 -0
- package/adapters/shared/recipe-harness-root.mjs +23 -0
- package/adapters/shared/resolve-farmslot-ports-core.mjs +205 -0
- package/adapters/shared/resolve-farmslot-ports.mjs +20 -0
- package/adapters/shared/resolve-farmslot-ports.sh +19 -126
- package/bin/mm-harness +45 -4
- package/dist/adapters/extension/runtime.js +3 -1
- package/dist/adapters/mobile/provision.js +34 -1
- package/dist/adapters/mobile/runtime-decision.js +3 -1
- package/dist/adapters/resolve-farmslot-ports.js +22 -0
- package/dist/adapters/slot-ports.js +18 -29
- package/dist/cli.js +32 -1463
- package/dist/commands/call.js +183 -0
- package/dist/commands/completion-candidates.js +58 -0
- package/dist/commands/doctor.js +101 -0
- package/dist/commands/ensure-ready.js +24 -0
- package/dist/commands/flows.js +62 -0
- package/dist/commands/launch/extension.js +40 -0
- package/dist/commands/{launch.js → launch/index.js} +15 -47
- package/dist/commands/launch/mobile.js +10 -0
- package/dist/commands/manifest.js +72 -0
- package/dist/commands/parse-args.js +189 -0
- package/dist/commands/provision.js +136 -0
- package/dist/commands/resolve-extension.js +23 -0
- package/dist/commands/run-engine.js +341 -0
- package/dist/commands/run.js +217 -0
- package/dist/commands/runtime-decision.js +58 -0
- package/dist/commands/runtime-health.js +25 -0
- package/dist/commands/runtime-launch.js +139 -0
- package/dist/commands/self-test.js +52 -0
- package/dist/commands/stop.js +52 -0
- package/dist/harness.js +8 -48
- package/dist/mm-harness-cli.js +13 -8
- package/docs/CLI-SPEC.md +1 -1
- package/docs/CODE-MAP.md +62 -0
- package/library/README.md +14 -0
- package/library/actions/core/perps/_controller.mjs +1 -1
- package/library/actions/extension/platform/cdp.mjs +2 -2
- package/library/actions/extension/wallet/ensure_unlocked.mjs +7 -1
- package/library/actions/harness-exports.mjs +27 -0
- package/library/actions/mobile/wallet/ensure_unlocked.mjs +14 -2
- package/library/actions/mobile/wallet/setup.mjs +1 -1
- package/package.json +6 -7
- package/src/adapters/core/surface.ts +0 -71
- package/src/adapters/extension/ensure-ready.ts +0 -185
- package/src/adapters/extension/extension-id.ts +0 -107
- package/src/adapters/extension/runtime-decision.ts +0 -445
- package/src/adapters/extension/runtime.ts +0 -407
- package/src/adapters/extension/surface.ts +0 -88
- package/src/adapters/mobile/deps-markers.ts +0 -21
- package/src/adapters/mobile/prepare.ts +0 -246
- package/src/adapters/mobile/provision.ts +0 -594
- package/src/adapters/mobile/runtime-decision.ts +0 -459
- package/src/adapters/mobile/surface.ts +0 -71
- package/src/adapters/slot-ports.ts +0 -165
- package/src/adapters/surface.ts +0 -117
- package/src/adapters.ts +0 -601
- package/src/cli-color.ts +0 -92
- package/src/cli-commands.ts +0 -250
- package/src/cli-version.ts +0 -141
- package/src/cli.ts +0 -2091
- package/src/commands/debug.ts +0 -65
- package/src/commands/fixtures.ts +0 -198
- package/src/commands/launch.ts +0 -470
- package/src/commands/logs.ts +0 -99
- package/src/commands/shared.ts +0 -235
- package/src/commands/update.ts +0 -316
- package/src/completions-cache.ts +0 -86
- package/src/doctor.ts +0 -215
- package/src/harness.ts +0 -797
- package/src/heal-bounds.ts +0 -198
- package/src/index.ts +0 -15
- package/src/leaf-invoke.ts +0 -28
- package/src/live-adapter-contract.ts +0 -274
- package/src/manifest.ts +0 -47
- package/src/mm-harness-cli.ts +0 -655
- package/src/paths.ts +0 -198
- package/src/progress.ts +0 -117
- package/src/recording-target.ts +0 -147
- package/src/run-recording.ts +0 -329
- package/src/runner.ts +0 -108
- package/src/types.ts +0 -57
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
// Mobile runtime prepare — in-process decision-and-action loop.
|
|
2
|
-
//
|
|
3
|
-
// Replaces the retired shell orchestrators (prepare-device.sh + launch.sh).
|
|
4
|
-
// All sequencing is in TypeScript; leaf shell scripts handle single OS ops.
|
|
5
|
-
// Control flows down only: TS → adapters/mobile/{yarn-setup,start-metro,open-device}.sh
|
|
6
|
-
// No leaf script may call back into mm-harness (A1).
|
|
7
|
-
|
|
8
|
-
import path from 'node:path';
|
|
9
|
-
|
|
10
|
-
import { recordDepsBaseline } from '@farmslot/recipe-harness/runtime/deps-readiness';
|
|
11
|
-
|
|
12
|
-
import { EXIT, spawnScriptStreaming } from '../../commands/shared.ts';
|
|
13
|
-
import type { ScriptResult } from '../../commands/shared.ts';
|
|
14
|
-
import { runnerDir } from '../../paths.ts';
|
|
15
|
-
import {
|
|
16
|
-
decideMobileReadiness,
|
|
17
|
-
type MobileRuntimeDecisionReport,
|
|
18
|
-
type MobileRuntimeDecisionOptions,
|
|
19
|
-
} from './runtime-decision.ts';
|
|
20
|
-
|
|
21
|
-
export { type MobileRuntimeDecisionReport };
|
|
22
|
-
|
|
23
|
-
// Pod install (run by `yarn setup` and by the native `yarn start:ios|android`
|
|
24
|
-
// build) shells `node --print require.resolve('react-native-worklets-core')` and
|
|
25
|
-
// treats any output other than the exact string `undefined` as "module found".
|
|
26
|
-
// An inherited FORCE_COLOR makes node emit a colorized `undefined`, so VisionCamera
|
|
27
|
-
// misdetects the worklets pod, enables FrameProcessors, and fails on the missing
|
|
28
|
-
// pod. Force plain output for pod-triggering spawns so the probe reads `undefined`.
|
|
29
|
-
// CocoaPods reads UTF-8 podspecs; a parent env without a locale (gateway/tmux
|
|
30
|
-
// spawns) makes Ruby parse them as US-ASCII and die on the first multibyte byte
|
|
31
|
-
// ('"\xE2" on US-ASCII' in react-native-mmkv.podspec). Pin a UTF-8 locale for
|
|
32
|
-
// pod-triggering spawns when the caller has none.
|
|
33
|
-
const POD_PROBE_ENV: Record<string, string> = {
|
|
34
|
-
FORCE_COLOR: '0',
|
|
35
|
-
NO_COLOR: '1',
|
|
36
|
-
LANG: process.env.LANG?.includes('UTF-8') ? process.env.LANG : 'en_US.UTF-8',
|
|
37
|
-
LC_ALL: process.env.LC_ALL?.includes('UTF-8') ? process.env.LC_ALL : 'en_US.UTF-8',
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
export interface PrepareMobileOptions extends MobileRuntimeDecisionOptions {
|
|
41
|
-
/**
|
|
42
|
-
* Whether the caller emits a --json envelope on stdout. Leaf progress always
|
|
43
|
-
* streams to stderr (see dispatchAction/spawnScriptStreaming); this only gates
|
|
44
|
-
* the in-process teaching messages so they never pollute the stdout envelope.
|
|
45
|
-
*/
|
|
46
|
-
json?: boolean;
|
|
47
|
-
/**
|
|
48
|
-
* Passed to open-device.sh --preflight-mode.
|
|
49
|
-
* 'fast' = error if not installed; 'auto' = install if missing; 'rebuild-native'/'clean' = always rebuild.
|
|
50
|
-
* Defaults to 'fast'.
|
|
51
|
-
*/
|
|
52
|
-
preflightMode?: string;
|
|
53
|
-
/**
|
|
54
|
-
* Force --clear on start-metro (reset bundle cache).
|
|
55
|
-
* Used by the setup-wallet clean-Metro retry path (M3).
|
|
56
|
-
*/
|
|
57
|
-
clearMetro?: boolean;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Read current runtime readiness without executing any action.
|
|
62
|
-
* No side effects: just calls decideMobileReadiness and returns the report.
|
|
63
|
-
*/
|
|
64
|
-
export async function mobileRuntimeStatus(
|
|
65
|
-
target: string,
|
|
66
|
-
opts: PrepareMobileOptions = {},
|
|
67
|
-
): Promise<MobileRuntimeDecisionReport> {
|
|
68
|
-
return decideMobileReadiness(target, {
|
|
69
|
-
watcherPort: opts.watcherPort,
|
|
70
|
-
metroLog: opts.metroLog,
|
|
71
|
-
platform: opts.platform,
|
|
72
|
-
record: opts.record,
|
|
73
|
-
preflightMode: opts.preflightMode,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Prepare the mobile runtime: run the readiness decision then execute each
|
|
79
|
-
* action in sequence via single-purpose leaf shell scripts. Returns a
|
|
80
|
-
* ScriptResult so the launch heal loop can classify outcomes uniformly.
|
|
81
|
-
*/
|
|
82
|
-
export async function prepareMobile(
|
|
83
|
-
target: string,
|
|
84
|
-
opts: PrepareMobileOptions = {},
|
|
85
|
-
): Promise<ScriptResult> {
|
|
86
|
-
const json = opts.json ?? false;
|
|
87
|
-
const platform = opts.platform ?? 'ios';
|
|
88
|
-
const preflightMode = opts.preflightMode ?? 'fast';
|
|
89
|
-
const clearMetro = opts.clearMetro ?? false;
|
|
90
|
-
|
|
91
|
-
const report = await decideMobileReadiness(target, {
|
|
92
|
-
watcherPort: opts.watcherPort,
|
|
93
|
-
metroLog: opts.metroLog,
|
|
94
|
-
platform,
|
|
95
|
-
record: opts.record,
|
|
96
|
-
preflightMode,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
if (report.decision === 'blocked') {
|
|
100
|
-
const reasons = report.reasons.join(' ');
|
|
101
|
-
const next = report.userAction ?? 'fix the bundle error in app code before retrying recipe up.';
|
|
102
|
-
const msg = `mobile prepare blocked: ${reasons}\n Next: ${next}`;
|
|
103
|
-
if (!json) process.stderr.write(`${msg}\n`);
|
|
104
|
-
return { status: EXIT.runtime, output: msg };
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (report.decision === 'ready') {
|
|
108
|
-
return { status: 0, output: '' };
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (report.decision === 'unknown') {
|
|
112
|
-
const msg = 'mobile prepare: runtime state unknown\n Next: run mm-harness verify --adapter mobile --target <checkout>';
|
|
113
|
-
if (!json) process.stderr.write(`${msg}\n`);
|
|
114
|
-
return { status: EXIT.runtime, output: msg };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// decision is 'install' or 'launch' — execute each action in sequence.
|
|
118
|
-
// clearMetro forces --clear on start-metro regardless of what decideMobileReadiness set.
|
|
119
|
-
const actions = clearMetro
|
|
120
|
-
? report.actions.map((a) =>
|
|
121
|
-
a.id === 'start-metro' && !a.argv?.includes('--clear')
|
|
122
|
-
? { ...a, argv: [...(a.argv ?? []), '--clear'] }
|
|
123
|
-
: a,
|
|
124
|
-
)
|
|
125
|
-
: report.actions;
|
|
126
|
-
for (const action of actions) {
|
|
127
|
-
const result = await dispatchAction(action, target, platform, json, preflightMode);
|
|
128
|
-
if (result.status !== 0) return result;
|
|
129
|
-
// Record the deps baseline the instant a setup/install leaf succeeds, so the
|
|
130
|
-
// mtime freshness fallback stops firing forever after one good install. This
|
|
131
|
-
// is unconditional (not gated on a later re-decide or an env flag), so the
|
|
132
|
-
// baseline lifecycle is self-sustaining regardless of the caller's path.
|
|
133
|
-
if (action.id === 'yarn-setup') recordDepsBaseline(path.resolve(target));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// After install: re-decide and run appropriate actions.
|
|
137
|
-
// RECIPE_UP_INSTALL_ATTEMPTED guards against infinite loops if yarn-setup was a no-op.
|
|
138
|
-
if (report.decision === 'install' && !process.env['RECIPE_UP_INSTALL_ATTEMPTED']) {
|
|
139
|
-
process.env['RECIPE_UP_INSTALL_ATTEMPTED'] = '1';
|
|
140
|
-
const postInstall = await decideMobileReadiness(target, {
|
|
141
|
-
watcherPort: opts.watcherPort,
|
|
142
|
-
metroLog: opts.metroLog,
|
|
143
|
-
platform,
|
|
144
|
-
preflightMode,
|
|
145
|
-
});
|
|
146
|
-
switch (postInstall.decision) {
|
|
147
|
-
case 'install': {
|
|
148
|
-
// Yarn setup ran but runtime is still unresolved — teach and fail.
|
|
149
|
-
const msg =
|
|
150
|
-
`mobile prepare: dependencies installed but runtime is still unresolved ` +
|
|
151
|
-
`(${postInstall.reasons.join('; ')})\n` +
|
|
152
|
-
` Next: inspect the checkout — node_modules may be incomplete or yarn.lock drifted.`;
|
|
153
|
-
if (!json) process.stderr.write(`${msg}\n`);
|
|
154
|
-
return { status: EXIT.runtime, output: msg };
|
|
155
|
-
}
|
|
156
|
-
case 'ready': {
|
|
157
|
-
// Deps resolved and runtime appears ready — still confirm bridge is live.
|
|
158
|
-
const bridge = await dispatchAction({ id: 'wait-for-bridge', cwd: target }, target, platform, json, preflightMode);
|
|
159
|
-
if (bridge.status !== 0) return bridge;
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
case 'launch': {
|
|
163
|
-
for (const action of postInstall.actions) {
|
|
164
|
-
const result = await dispatchAction(action, target, platform, json, preflightMode);
|
|
165
|
-
if (result.status !== 0) return result;
|
|
166
|
-
}
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
default: {
|
|
170
|
-
// 'blocked' or 'unknown' after install — surface as error.
|
|
171
|
-
const msg =
|
|
172
|
-
`mobile prepare: post-install state is ${postInstall.decision}: ${postInstall.reasons.join('; ')}\n` +
|
|
173
|
-
` Next: run mm-harness verify --adapter mobile --target <checkout>`;
|
|
174
|
-
if (!json) process.stderr.write(`${msg}\n`);
|
|
175
|
-
return { status: EXIT.runtime, output: msg };
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return { status: 0, output: '' };
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Long-running leaves stream their output to stderr live (spawnScriptStreaming),
|
|
184
|
-
// so the multi-minute prepare phase is not silent; stdout stays reserved for the
|
|
185
|
-
// caller's --json envelope. Async so the parent can await each leaf in sequence.
|
|
186
|
-
async function dispatchAction(
|
|
187
|
-
action: { id: string; argv?: string[]; cwd?: string },
|
|
188
|
-
target: string,
|
|
189
|
-
platform: string,
|
|
190
|
-
json: boolean,
|
|
191
|
-
preflightMode = 'fast',
|
|
192
|
-
): Promise<ScriptResult> {
|
|
193
|
-
const cwd = action.cwd ?? target;
|
|
194
|
-
switch (action.id) {
|
|
195
|
-
case 'yarn-setup': {
|
|
196
|
-
// Leaf: install node_modules (deps missing or stale); `yarn setup` runs pods.
|
|
197
|
-
const leaf = path.join(runnerDir, 'adapters/mobile/yarn-setup.sh');
|
|
198
|
-
return spawnScriptStreaming(leaf, ['--target', cwd], target, POD_PROBE_ENV);
|
|
199
|
-
}
|
|
200
|
-
case 'start-metro': {
|
|
201
|
-
// Leaf: ensure Metro is running; argv may carry --clear for cache reset.
|
|
202
|
-
const leaf = path.join(runnerDir, 'adapters/mobile/start-metro.sh');
|
|
203
|
-
const extra: string[] = action.argv ?? [];
|
|
204
|
-
return spawnScriptStreaming(leaf, ['--target', cwd, ...extra], target);
|
|
205
|
-
}
|
|
206
|
-
case 'prewarm-bundle': {
|
|
207
|
-
// Leaf: curl the bundle URL before opening the dev client.
|
|
208
|
-
const leaf = path.join(runnerDir, 'adapters/mobile/prewarm-bundle.sh');
|
|
209
|
-
return spawnScriptStreaming(leaf, ['--platform', platform, '--target', cwd], target);
|
|
210
|
-
}
|
|
211
|
-
case 'wait-for-bridge': {
|
|
212
|
-
// Leaf: poll CDP bridge until a route target registers.
|
|
213
|
-
const leaf = path.join(runnerDir, 'adapters/mobile/wait-for-bridge.sh');
|
|
214
|
-
return spawnScriptStreaming(leaf, ['--target', cwd], target);
|
|
215
|
-
}
|
|
216
|
-
case 'clear-metro-cache': {
|
|
217
|
-
// Legacy alias for start-metro --clear (kept for backward compat).
|
|
218
|
-
const leaf = path.join(runnerDir, 'adapters/mobile/start-metro.sh');
|
|
219
|
-
return spawnScriptStreaming(leaf, ['--target', cwd, '--clear'], target);
|
|
220
|
-
}
|
|
221
|
-
case 'launch-mobile-runtime': {
|
|
222
|
-
// Leaf: open the MetaMask Mobile dev client on the simulator/device. In
|
|
223
|
-
// auto/rebuild modes this runs the native build (`yarn start:*`), which
|
|
224
|
-
// triggers pod install — pass the pod-probe env so it stays FORCE_COLOR-safe.
|
|
225
|
-
const leaf = path.join(runnerDir, 'adapters/mobile/open-device.sh');
|
|
226
|
-
return spawnScriptStreaming(
|
|
227
|
-
leaf,
|
|
228
|
-
['--platform', platform, '--target', cwd, '--preflight-mode', preflightMode],
|
|
229
|
-
target,
|
|
230
|
-
POD_PROBE_ENV,
|
|
231
|
-
);
|
|
232
|
-
}
|
|
233
|
-
case 'rebuild-native-dev-client': {
|
|
234
|
-
// Native rebuild required — the dev client binary predates a native Nitro
|
|
235
|
-
// module. Inform the caller; a full native build is not automated here.
|
|
236
|
-
const msg =
|
|
237
|
-
'rebuild-native-dev-client required: native module mismatch detected.\n' +
|
|
238
|
-
' Next: yarn start:ios or yarn start:android to rebuild the native dev client, ' +
|
|
239
|
-
'then re-run mm-harness launch.';
|
|
240
|
-
if (!json) process.stderr.write(`${msg}\n`);
|
|
241
|
-
return { status: EXIT.runtime, output: msg };
|
|
242
|
-
}
|
|
243
|
-
default:
|
|
244
|
-
return { status: 0, output: '' };
|
|
245
|
-
}
|
|
246
|
-
}
|