@deeeed/metamask-harness 0.2.0 → 0.3.1
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 +33 -0
- package/README.md +47 -17
- package/{orchestration → adapters}/core/cleanup.sh +2 -2
- package/{orchestration → adapters}/core/inject.sh +8 -8
- package/{orchestration → adapters}/extension/cleanup.mjs +1 -1
- package/{orchestration → adapters}/extension/console-tail.mjs +3 -0
- package/{orchestration → adapters}/extension/ensure-browser.sh +4 -4
- package/{orchestration → adapters}/extension/inject.mjs +27 -31
- package/{orchestration → adapters}/extension/launch.sh +4 -4
- package/{orchestration → adapters}/extension/live.sh +5 -5
- package/{orchestration → adapters}/extension/readiness.mjs +12 -2
- package/{orchestration → adapters}/extension/refresh-build.sh +1 -1
- package/{orchestration → adapters}/extension/seed-fixture.sh +1 -1
- package/{orchestration → adapters}/extension/start-watch.sh +7 -7
- package/{runner → adapters}/extension/verify.sh +11 -11
- package/{orchestration → adapters}/extension/wallet-fixture-state.cjs +2 -2
- package/{orchestration → adapters}/manifest.json +96 -96
- package/{library/actions → adapters}/mobile/bridge-runtime/cdp-bridge.cjs +5 -5
- package/{orchestration → adapters}/mobile/cleanup.sh +3 -3
- package/{orchestration → adapters}/mobile/inject.sh +22 -24
- package/adapters/mobile/open-device.sh +260 -0
- package/{orchestration/compat-overlays → adapters/mobile/overlay/compat}/README.md +13 -4
- package/adapters/mobile/prewarm-bundle.sh +95 -0
- package/adapters/mobile/start-metro.sh +228 -0
- package/{runner → adapters}/mobile/verify.sh +6 -6
- package/adapters/mobile/wait-for-bridge.sh +108 -0
- package/adapters/mobile/yarn-setup.sh +20 -0
- package/{orchestration/lib → adapters/shared}/cli-ux.sh +5 -9
- package/{orchestration/lib → adapters/shared}/log-tui.mjs +57 -1
- package/{orchestration/lib → adapters/shared}/open-debug.mjs +32 -10
- package/{orchestration/lib → adapters/shared}/resolve-farmslot-ports.sh +47 -0
- package/adapters/shared/sync-wallet-fixture.sh +78 -0
- package/bin/mm-harness +37 -6
- package/docs/CLI-SPEC.md +41 -2
- package/docs/architecture.md +69 -38
- package/docs/runtime-file-conventions.md +3 -3
- 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 +1 -1
- package/library/actions/mobile/platform/bridge.mjs +1 -1
- package/library/actions/mobile/wallet/ensure_unlocked.mjs +1 -1
- package/library/actions/mobile/wallet/setup.mjs +2 -2
- package/library/library.json +1 -1
- package/package.json +8 -8
- package/{orchestration → src/adapters}/extension/runtime-decision.ts +5 -5
- package/{orchestration → src/adapters}/extension/runtime.ts +1 -1
- package/src/adapters/mobile/prepare.ts +210 -0
- package/{orchestration → src/adapters}/mobile/runtime-decision.ts +105 -5
- package/{runner/src → src}/adapters.ts +3 -3
- package/{orchestration/lib/cli-color.mjs → src/cli-color.ts} +21 -13
- package/{orchestration/lib/cli-commands.mjs → src/cli-commands.ts} +52 -45
- package/{orchestration/lib/cli-version.mjs → src/cli-version.ts} +35 -17
- package/{runner/src → src}/cli.ts +48 -40
- package/src/commands/debug.ts +63 -0
- package/src/commands/fixtures.ts +193 -0
- package/{runner/src → src}/commands/launch.ts +200 -54
- package/src/commands/logs.ts +83 -0
- package/{runner/src → src}/commands/shared.ts +40 -30
- package/src/commands/update.ts +316 -0
- package/{runner/src → src}/harness.ts +119 -16
- package/{runner/src → src}/heal-bounds.ts +20 -1
- package/src/index.ts +15 -0
- package/{runner/src → src}/live-adapter-contract.ts +1 -1
- package/{runner/src → src}/mm-harness-cli.ts +64 -3
- package/{runner/src → src}/paths.ts +2 -2
- package/{orchestration/lib/progress.mjs → src/progress.ts} +31 -21
- package/docs/extension-runtime-commands.md +0 -60
- package/docs/harness-cli.md +0 -43
- package/orchestration/compat-overlays/mobile/README.md +0 -13
- package/orchestration/doctor.mjs +0 -72
- package/orchestration/lib/cli-home.mjs +0 -354
- package/orchestration/lib/recipe-paths.mjs +0 -26
- package/orchestration/mobile/launch.sh +0 -137
- package/orchestration/mobile/live.sh +0 -125
- package/orchestration/porcelain/metamask-recipe +0 -99
- package/orchestration/porcelain/mm-recipe +0 -1591
- package/orchestration/porcelain/mme-recipe +0 -1181
- package/runner/src/commands/debug.ts +0 -44
- package/runner/src/commands/fixtures.ts +0 -99
- package/runner/src/commands/logs.ts +0 -60
- package/runner/src/index.ts +0 -6
- /package/{orchestration → adapters}/extension/launch-browser.cjs +0 -0
- /package/{orchestration → adapters}/extension/pin-remote-flags.cjs +0 -0
- /package/{orchestration → adapters}/extension/sidepanel-toggle.sh +0 -0
- /package/{orchestration → adapters}/extension/snapshot-dist.sh +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/cdp-eval.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/config.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/issue-capture.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/target-discovery.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/lib/ws-client.cjs +0 -0
- /package/{library/actions → adapters}/mobile/bridge-runtime/setup-wallet.sh +0 -0
- /package/{library/actions/mobile/app-overlay → adapters/mobile/overlay}/app/dev-tools/AgenticService/AgentStepHud.tsx.patch +0 -0
- /package/{library/actions/mobile/app-overlay → adapters/mobile/overlay}/app/dev-tools/AgenticService/AgenticService.ts.patch +0 -0
- /package/{orchestration/compat-overlays/mobile → adapters/mobile/overlay/compat}/rn81-message-event-source.patch +0 -0
- /package/{orchestration/lib → adapters/shared}/activate-repo-node.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/ensure-runner-deps.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/harness-path.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/hash-helpers.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/json-field.sh +0 -0
- /package/{orchestration/lib → adapters/shared}/path-defaults.json +0 -0
- /package/{orchestration → src/adapters}/extension/ensure-ready.ts +0 -0
- /package/{orchestration → src/adapters}/extension/extension-id.ts +0 -0
- /package/{orchestration → src/adapters}/mobile/deps-markers.ts +0 -0
- /package/{runner/src → src}/completions-cache.ts +0 -0
- /package/{runner/src → src}/doctor.ts +0 -0
- /package/{runner/src → src}/manifest.ts +0 -0
- /package/{runner/src → src}/recording-target.ts +0 -0
- /package/{runner/src → src}/run-recording.ts +0 -0
- /package/{runner/src → src}/runner.ts +0 -0
- /package/{runner/src → src}/types.ts +0 -0
|
@@ -1,15 +1,26 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
/**
|
|
3
|
-
* cli-commands.
|
|
2
|
+
* cli-commands.ts — single source of truth for recipe CLI tab completion.
|
|
4
3
|
*/
|
|
5
4
|
import fs from 'node:fs';
|
|
6
5
|
import path from 'node:path';
|
|
7
6
|
import { fileURLToPath } from 'node:url';
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
interface CommandSpec {
|
|
9
|
+
name: string;
|
|
10
|
+
aliases?: string[];
|
|
11
|
+
desc?: string;
|
|
12
|
+
flags?: string[];
|
|
13
|
+
args?: string[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface CommandSpecMap {
|
|
17
|
+
shared: CommandSpec[];
|
|
18
|
+
extension: CommandSpec[];
|
|
19
|
+
mobile: CommandSpec[];
|
|
20
|
+
shim: CommandSpec[];
|
|
21
|
+
}
|
|
10
22
|
|
|
11
|
-
|
|
12
|
-
export const SPEC = {
|
|
23
|
+
export const SPEC: CommandSpecMap = {
|
|
13
24
|
shim: [
|
|
14
25
|
{ name: 'sync', desc: 'Copy fixture, write slot context, install harness', flags: ['--dry-run', '--no-install'] },
|
|
15
26
|
{ name: 'help', aliases: ['-h', '--help'], desc: 'Show usage' },
|
|
@@ -34,9 +45,7 @@ export const SPEC = {
|
|
|
34
45
|
{ name: 'ready', aliases: ['ensure-ready'], desc: 'Ensure one healthy extension home tab' },
|
|
35
46
|
{ name: 'watch', aliases: ['start-watch', 'watcher'], desc: 'Start/reuse webpack watcher', flags: ['--full', '-f'] },
|
|
36
47
|
{ name: 'stop', aliases: ['stop-watch', 'stop-watcher'], desc: 'Stop this checkout watcher' },
|
|
37
|
-
{ name: 'rebuild', aliases: ['reset', 'reopen', 'reload', 'browser', 'launch', 'full-launch', 'runtime-launch'], desc: 'Clean webpack + browser launch', flags: ['--json', '--dry-run', '--full'] },
|
|
38
|
-
{ name: 'refresh', aliases: ['build'], desc: 'Fast refresh with active watcher' },
|
|
39
|
-
{ name: 'refresh:once', aliases: ['refresh-once', 'build:once', 'build-once'], desc: 'One-shot refresh-build helper' },
|
|
48
|
+
{ name: 'rebuild', aliases: ['reset', 'reopen', 'reload', 'browser', 'launch', 'full-launch', 'runtime-launch', 'build', 'build:once', 'build-once', 'refresh-once'], desc: 'Clean webpack + browser launch', flags: ['--json', '--dry-run', '--full'] },
|
|
40
49
|
{ name: 'sidepanel', desc: 'Side panel helper', args: ['cycle', 'open', 'close', 'toggle', 'status'] },
|
|
41
50
|
{ name: 'prepare', flags: ['--target', '--cdp-port', '--runtime-dir', '--validate'] },
|
|
42
51
|
{ name: 'debug', args: ['page', 'worker'], flags: ['--json', '--no-open'] },
|
|
@@ -46,7 +55,6 @@ export const SPEC = {
|
|
|
46
55
|
{ name: 'android', desc: 'Start Metro + launch Android dev client' },
|
|
47
56
|
{ name: 'setup:ios', desc: 'iOS launch + wallet fixture setup' },
|
|
48
57
|
{ name: 'setup:android', desc: 'Android launch + wallet fixture setup' },
|
|
49
|
-
{ name: 'refresh', aliases: ['reload', 'relaunch'], desc: 'Refresh Metro + relaunch dev client' },
|
|
50
58
|
{ name: 'stop', desc: 'Stop Metro for this slot' },
|
|
51
59
|
{ name: 'app-status', aliases: ['bridge-status'], desc: 'Bridge/runtime status' },
|
|
52
60
|
{ name: 'route', aliases: ['get-route'], desc: 'Current navigation route' },
|
|
@@ -65,9 +73,9 @@ export const SPEC = {
|
|
|
65
73
|
|
|
66
74
|
const GLOBAL_FLAGS = ['--json', '--dry-run', '--full', '-f', '--help', '-h', '--no-open', '--no-color'];
|
|
67
75
|
|
|
68
|
-
function mergeCommands(adapter) {
|
|
69
|
-
const byName = new Map();
|
|
70
|
-
const add = (cmd) => {
|
|
76
|
+
function mergeCommands(adapter: string): CommandSpec[] {
|
|
77
|
+
const byName = new Map<string, CommandSpec & { aliases: string[]; flags: string[]; args: string[] }>();
|
|
78
|
+
const add = (cmd: CommandSpec) => {
|
|
71
79
|
const existing = byName.get(cmd.name);
|
|
72
80
|
if (!existing) {
|
|
73
81
|
byName.set(cmd.name, {
|
|
@@ -84,12 +92,12 @@ function mergeCommands(adapter) {
|
|
|
84
92
|
if (!existing.desc && cmd.desc) existing.desc = cmd.desc;
|
|
85
93
|
};
|
|
86
94
|
for (const cmd of SPEC.shared) add(cmd);
|
|
87
|
-
for (const cmd of SPEC[adapter] || []) add(cmd);
|
|
95
|
+
for (const cmd of SPEC[adapter as keyof CommandSpecMap] || []) add(cmd);
|
|
88
96
|
return [...byName.values()];
|
|
89
97
|
}
|
|
90
98
|
|
|
91
|
-
export function commandTokens(adapter, { includeAliases = true } = {}) {
|
|
92
|
-
const tokens = new Set();
|
|
99
|
+
export function commandTokens(adapter: string, { includeAliases = true }: { includeAliases?: boolean } = {}): string[] {
|
|
100
|
+
const tokens = new Set<string>();
|
|
93
101
|
for (const cmd of mergeCommands(adapter)) {
|
|
94
102
|
tokens.add(cmd.name);
|
|
95
103
|
if (includeAliases) for (const alias of cmd.aliases || []) tokens.add(alias);
|
|
@@ -97,8 +105,8 @@ export function commandTokens(adapter, { includeAliases = true } = {}) {
|
|
|
97
105
|
return [...tokens].sort();
|
|
98
106
|
}
|
|
99
107
|
|
|
100
|
-
export function shimCommandTokens() {
|
|
101
|
-
const tokens = new Set();
|
|
108
|
+
export function shimCommandTokens(): string[] {
|
|
109
|
+
const tokens = new Set<string>();
|
|
102
110
|
for (const cmd of SPEC.shim) {
|
|
103
111
|
tokens.add(cmd.name);
|
|
104
112
|
for (const alias of cmd.aliases || []) tokens.add(alias);
|
|
@@ -106,7 +114,7 @@ export function shimCommandTokens() {
|
|
|
106
114
|
return [...tokens].sort();
|
|
107
115
|
}
|
|
108
116
|
|
|
109
|
-
export function lookupCommand(adapter, token) {
|
|
117
|
+
export function lookupCommand(adapter: string, token: string): CommandSpec | null {
|
|
110
118
|
for (const cmd of mergeCommands(adapter)) {
|
|
111
119
|
if (cmd.name === token) return cmd;
|
|
112
120
|
if ((cmd.aliases || []).includes(token)) return cmd;
|
|
@@ -118,28 +126,27 @@ export function lookupCommand(adapter, token) {
|
|
|
118
126
|
return null;
|
|
119
127
|
}
|
|
120
128
|
|
|
121
|
-
export function flagsForPosition(adapter, commandToken) {
|
|
129
|
+
export function flagsForPosition(adapter: string, commandToken: string): string[] {
|
|
122
130
|
const cmd = lookupCommand(adapter, commandToken);
|
|
123
131
|
const flags = new Set(GLOBAL_FLAGS);
|
|
124
132
|
if (cmd) for (const flag of cmd.flags || []) flags.add(flag);
|
|
125
133
|
return [...flags].sort();
|
|
126
134
|
}
|
|
127
135
|
|
|
128
|
-
export function argsForPosition(adapter, commandToken, argIndex) {
|
|
136
|
+
export function argsForPosition(adapter: string, commandToken: string, argIndex: number): string[] {
|
|
129
137
|
const cmd = lookupCommand(adapter, commandToken);
|
|
130
138
|
if (!cmd?.args?.length) return [];
|
|
131
139
|
const value = cmd.args[Math.max(0, argIndex)];
|
|
132
140
|
return value ? [value] : cmd.args;
|
|
133
141
|
}
|
|
134
142
|
|
|
135
|
-
const RUN_RECIPE_DIRS = [
|
|
143
|
+
const RUN_RECIPE_DIRS: ((adapter: string, root: string) => string)[] = [
|
|
136
144
|
(adapter, root) => path.join(root, 'temp/recipe/harness', adapter, 'runner/recipes'),
|
|
137
145
|
(adapter, root) => path.join(root, 'temp/agentic/recipe-harness', adapter, 'runner/recipes'),
|
|
138
146
|
];
|
|
139
147
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const byBase = new Map();
|
|
148
|
+
export function listRunRecipes(adapter: string, root: string, cwd = process.cwd()): string[] {
|
|
149
|
+
const byBase = new Map<string, string>();
|
|
143
150
|
for (const resolveDir of RUN_RECIPE_DIRS) {
|
|
144
151
|
const dir = resolveDir(adapter, root);
|
|
145
152
|
if (!fs.existsSync(dir)) continue;
|
|
@@ -153,20 +160,20 @@ export function listRunRecipes(adapter, root, cwd = process.cwd()) {
|
|
|
153
160
|
.sort();
|
|
154
161
|
}
|
|
155
162
|
|
|
156
|
-
function usage() {
|
|
163
|
+
function usage(): void {
|
|
157
164
|
process.stderr.write(`Usage:
|
|
158
|
-
cli-commands
|
|
159
|
-
cli-commands
|
|
160
|
-
cli-commands
|
|
161
|
-
cli-commands
|
|
162
|
-
cli-commands
|
|
163
|
-
cli-commands
|
|
165
|
+
cli-commands dump --adapter extension|mobile|shim [--aliases]
|
|
166
|
+
cli-commands describe --adapter extension|mobile|shim
|
|
167
|
+
cli-commands flags --adapter <adapter> --command <name>
|
|
168
|
+
cli-commands args --adapter <adapter> --command <name> [--index <n>]
|
|
169
|
+
cli-commands run-recipes --adapter extension|mobile --root <repo> [--cwd <dir>]
|
|
170
|
+
cli-commands global-flags
|
|
164
171
|
`);
|
|
165
172
|
}
|
|
166
173
|
|
|
167
|
-
async function main() {
|
|
168
|
-
const { parseArgs } = await import('node:util');
|
|
169
|
-
const { values, positionals } =
|
|
174
|
+
async function main(): Promise<void> {
|
|
175
|
+
const { parseArgs: parseArgsUtil } = await import('node:util');
|
|
176
|
+
const { values, positionals } = parseArgsUtil({
|
|
170
177
|
allowPositionals: true,
|
|
171
178
|
args: process.argv.slice(2),
|
|
172
179
|
options: {
|
|
@@ -197,12 +204,12 @@ async function main() {
|
|
|
197
204
|
}
|
|
198
205
|
|
|
199
206
|
if (command === 'dump') {
|
|
200
|
-
process.stdout.write(`${commandTokens(adapter, { includeAliases: values.aliases }).join('\n')}\n`);
|
|
207
|
+
process.stdout.write(`${commandTokens(adapter as string, { includeAliases: values.aliases }).join('\n')}\n`);
|
|
201
208
|
return;
|
|
202
209
|
}
|
|
203
210
|
|
|
204
211
|
if (command === 'describe') {
|
|
205
|
-
const rows = adapter === 'shim' ? SPEC.shim : mergeCommands(adapter);
|
|
212
|
+
const rows = adapter === 'shim' ? SPEC.shim : mergeCommands(adapter as string);
|
|
206
213
|
for (const cmd of rows) {
|
|
207
214
|
const aliases = (cmd.aliases || []).join('|');
|
|
208
215
|
const label = aliases ? `${cmd.name}|${aliases}` : cmd.name;
|
|
@@ -212,20 +219,20 @@ async function main() {
|
|
|
212
219
|
}
|
|
213
220
|
|
|
214
221
|
if (command === 'flags') {
|
|
215
|
-
process.stdout.write(`${flagsForPosition(adapter, values.command || '').join('\n')}\n`);
|
|
222
|
+
process.stdout.write(`${flagsForPosition(adapter as string, values.command || '').join('\n')}\n`);
|
|
216
223
|
return;
|
|
217
224
|
}
|
|
218
225
|
|
|
219
226
|
if (command === 'args') {
|
|
220
|
-
const index = Number.parseInt(values.index, 10) || 0;
|
|
221
|
-
process.stdout.write(`${argsForPosition(adapter, values.command || '', index).join('\n')}\n`);
|
|
227
|
+
const index = Number.parseInt(values.index as string, 10) || 0;
|
|
228
|
+
process.stdout.write(`${argsForPosition(adapter as string, values.command || '', index).join('\n')}\n`);
|
|
222
229
|
return;
|
|
223
230
|
}
|
|
224
231
|
|
|
225
232
|
if (command === 'run-recipes') {
|
|
226
233
|
const root = values.root ? path.resolve(values.root) : process.cwd();
|
|
227
234
|
const cwd = values.cwd ? path.resolve(values.cwd) : process.cwd();
|
|
228
|
-
process.stdout.write(`${listRunRecipes(adapter, root, cwd).join('\n')}\n`);
|
|
235
|
+
process.stdout.write(`${listRunRecipes(adapter as string, root, cwd).join('\n')}\n`);
|
|
229
236
|
return;
|
|
230
237
|
}
|
|
231
238
|
|
|
@@ -233,11 +240,11 @@ async function main() {
|
|
|
233
240
|
process.exit(2);
|
|
234
241
|
}
|
|
235
242
|
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
if (
|
|
239
|
-
main().catch((error) => {
|
|
243
|
+
const _filename = fileURLToPath(import.meta.url);
|
|
244
|
+
const isMain = process.argv[1] && path.resolve(process.argv[1]) === _filename;
|
|
245
|
+
if (isMain) {
|
|
246
|
+
main().catch((error: unknown) => {
|
|
240
247
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
241
248
|
process.exit(1);
|
|
242
249
|
});
|
|
243
|
-
}
|
|
250
|
+
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
/**
|
|
3
|
-
* cli-version.
|
|
2
|
+
* cli-version.ts — detect stale installed harness scripts vs the active runner.
|
|
4
3
|
*/
|
|
5
4
|
import fs from 'node:fs';
|
|
6
5
|
import path from 'node:path';
|
|
7
6
|
import { spawnSync } from 'node:child_process';
|
|
8
7
|
import { parseArgs } from 'node:util';
|
|
9
8
|
|
|
10
|
-
function readJson(file) {
|
|
9
|
+
function readJson(file: string): unknown {
|
|
11
10
|
try {
|
|
12
11
|
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
13
12
|
} catch {
|
|
@@ -15,31 +14,49 @@ function readJson(file) {
|
|
|
15
14
|
}
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
function readPackageVersion(dir) {
|
|
17
|
+
function readPackageVersion(dir: string): string {
|
|
19
18
|
try {
|
|
20
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
19
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8')) as { version?: string };
|
|
21
20
|
return pkg.version || 'unknown';
|
|
22
21
|
} catch {
|
|
23
22
|
return 'unknown';
|
|
24
23
|
}
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
function gitHead(dir) {
|
|
26
|
+
function gitHead(dir: string): string {
|
|
28
27
|
const result = spawnSync('git', ['-C', dir, 'rev-parse', 'HEAD'], { encoding: 'utf8' });
|
|
29
28
|
return result.status === 0 ? result.stdout.trim() : 'unknown';
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
interface HarnessCheckInput {
|
|
32
|
+
runnerRoot: string;
|
|
33
|
+
manifestPath: string;
|
|
34
|
+
installedShaPath?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface HarnessCheckResult {
|
|
38
|
+
stale: boolean;
|
|
39
|
+
reasons: string[];
|
|
40
|
+
installedRevision?: string | null;
|
|
41
|
+
currentRevision?: string;
|
|
42
|
+
installedVersion?: string | null;
|
|
43
|
+
currentVersion?: string;
|
|
44
|
+
manifest?: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function checkHarness({ runnerRoot, manifestPath }: HarnessCheckInput): HarnessCheckResult {
|
|
33
48
|
const manifest = readJson(manifestPath);
|
|
34
|
-
const reasons = [];
|
|
49
|
+
const reasons: string[] = [];
|
|
35
50
|
if (!manifest) {
|
|
36
51
|
return { stale: false, reasons: ['no harness manifest'] };
|
|
37
52
|
}
|
|
38
53
|
|
|
39
54
|
const currentRevision = gitHead(runnerRoot);
|
|
40
55
|
const currentVersion = readPackageVersion(runnerRoot);
|
|
41
|
-
const
|
|
42
|
-
const
|
|
56
|
+
const manifestRecord = manifest as Record<string, unknown>;
|
|
57
|
+
const source = manifestRecord.source as Record<string, unknown> | undefined;
|
|
58
|
+
const installedRevision = (source?.runnerRevision as string) || null;
|
|
59
|
+
const installedVersion = (manifestRecord.runnerPackageVersion as string) || null;
|
|
43
60
|
|
|
44
61
|
if (installedRevision && installedRevision !== 'unknown' && installedRevision !== currentRevision) {
|
|
45
62
|
reasons.push(`runner revision ${installedRevision.slice(0, 8)} != ${currentRevision.slice(0, 8)}`);
|
|
@@ -58,12 +75,12 @@ export function checkHarness({ runnerRoot, manifestPath, installedShaPath }) {
|
|
|
58
75
|
};
|
|
59
76
|
}
|
|
60
77
|
|
|
61
|
-
function usage() {
|
|
78
|
+
function usage(): void {
|
|
62
79
|
console.error(`Usage:
|
|
63
|
-
cli-version
|
|
80
|
+
cli-version check --runner-root <dir> --manifest <path> [--installed-sha <path>] [--json]`);
|
|
64
81
|
}
|
|
65
82
|
|
|
66
|
-
async function main() {
|
|
83
|
+
async function main(): Promise<void> {
|
|
67
84
|
const [command, ...rest] = process.argv.slice(2);
|
|
68
85
|
const { values } = parseArgs({
|
|
69
86
|
args: rest,
|
|
@@ -93,7 +110,7 @@ async function main() {
|
|
|
93
110
|
process.exit(2);
|
|
94
111
|
}
|
|
95
112
|
|
|
96
|
-
const payload = {
|
|
113
|
+
const payload: HarnessCheckResult & { manifest: string } = {
|
|
97
114
|
...checkHarness({
|
|
98
115
|
runnerRoot,
|
|
99
116
|
manifestPath,
|
|
@@ -115,9 +132,10 @@ async function main() {
|
|
|
115
132
|
process.stdout.write('harness up to date\n');
|
|
116
133
|
}
|
|
117
134
|
|
|
118
|
-
|
|
119
|
-
|
|
135
|
+
const isMain = process.argv[1] && path.resolve(process.argv[1]) === path.resolve(import.meta.filename ?? '');
|
|
136
|
+
if (isMain) {
|
|
137
|
+
main().catch((error: unknown) => {
|
|
120
138
|
console.error(error instanceof Error ? error.message : String(error));
|
|
121
139
|
process.exit(1);
|
|
122
140
|
});
|
|
123
|
-
}
|
|
141
|
+
}
|
|
@@ -23,10 +23,10 @@ import {
|
|
|
23
23
|
checkHealBounds,
|
|
24
24
|
} from './heal-bounds.ts';
|
|
25
25
|
import type { HealPolicy, HealState, HealBoundViolation } from './heal-bounds.ts';
|
|
26
|
-
import { ensureExtensionReady } from '
|
|
27
|
-
import { resolveExtensionId } from '
|
|
28
|
-
import { decideExtensionReadiness } from '
|
|
29
|
-
import { decideMobileReadiness } from '
|
|
26
|
+
import { ensureExtensionReady } from './adapters/extension/ensure-ready.ts';
|
|
27
|
+
import { resolveExtensionId } from './adapters/extension/extension-id.ts';
|
|
28
|
+
import { decideExtensionReadiness } from './adapters/extension/runtime-decision.ts';
|
|
29
|
+
import { decideMobileReadiness } from './adapters/mobile/runtime-decision.ts';
|
|
30
30
|
// NOTE: extension-runtime.ts loads the recipe harness at module scope, so it
|
|
31
31
|
// is imported LAZILY (dynamic import) only inside the handlers that drive a live
|
|
32
32
|
// runtime. Static-import it here and every command — manifest, doctor,
|
|
@@ -57,7 +57,7 @@ import type {
|
|
|
57
57
|
RecipeValidationResult,
|
|
58
58
|
} from '@farmslot/protocol';
|
|
59
59
|
import type { MetaMaskRecipeAdapter } from './types.ts';
|
|
60
|
-
import { usageOut } from './commands/shared.ts';
|
|
60
|
+
import { ADAPTER_DETECT_NEXT, usageOut } from './commands/shared.ts';
|
|
61
61
|
|
|
62
62
|
type CliOptionValue = string | boolean;
|
|
63
63
|
type CliOptions = Record<string, CliOptionValue>;
|
|
@@ -372,7 +372,7 @@ async function prepareRuntimeIfNeeded(
|
|
|
372
372
|
runtimeOptions: RuntimeOptions,
|
|
373
373
|
): Promise<void> {
|
|
374
374
|
if (adapter !== 'extension' || runtimeOptions.skipExtensionRuntimePrepare === true) return;
|
|
375
|
-
const { prepareExtensionRuntime } = await import('
|
|
375
|
+
const { prepareExtensionRuntime } = await import('./adapters/extension/runtime.ts');
|
|
376
376
|
await prepareExtensionRuntime({
|
|
377
377
|
projectRoot,
|
|
378
378
|
cdpPort: runtimeOptions.cdpPort,
|
|
@@ -390,7 +390,7 @@ function restoreEnv(key: string, value: string | undefined) {
|
|
|
390
390
|
async function runSelfTest(options: CliOptions) {
|
|
391
391
|
const root = optionString(options, 'artifactsDir')
|
|
392
392
|
? path.resolve(requiredOption(options, 'artifactsDir', 'self-test artifacts dir missing.'))
|
|
393
|
-
: await mkdtemp(path.join(os.tmpdir(), '
|
|
393
|
+
: await mkdtemp(path.join(os.tmpdir(), 'mm-harness-runner-'));
|
|
394
394
|
const previousAutoHud = process.env.METAMASK_RECIPE_AUTO_HUD;
|
|
395
395
|
const runs = [];
|
|
396
396
|
try {
|
|
@@ -455,11 +455,7 @@ async function handleDoctor({ options }: ParsedArgs): Promise<number> {
|
|
|
455
455
|
const explicitAdapter = optionString(options, 'adapter') ?? optionString(options, 'platform');
|
|
456
456
|
const adapter = explicitAdapter ?? detectAdapter(target);
|
|
457
457
|
if (!adapter) {
|
|
458
|
-
return usageOut(
|
|
459
|
-
json,
|
|
460
|
-
'doctor',
|
|
461
|
-
`could not detect the MetaMask repo type for ${target}\n Next: pass --adapter mobile|extension|core`,
|
|
462
|
-
);
|
|
458
|
+
return usageOut(json, 'doctor', `could not detect the MetaMask repo type for ${target}`, ADAPTER_DETECT_NEXT);
|
|
463
459
|
}
|
|
464
460
|
assertAdapter(adapter);
|
|
465
461
|
const actionManifestPath = actionManifestPathOption(options, adapter);
|
|
@@ -596,7 +592,7 @@ async function handleRuntimeHealth({ options }: ParsedArgs): Promise<number> {
|
|
|
596
592
|
optionString(options, 'cdpPort') ?? process.env.CDP_PORT ?? process.env.RECIPE_CDP_PORT,
|
|
597
593
|
'runtime-health requires --cdp-port <port>.',
|
|
598
594
|
);
|
|
599
|
-
const { checkExtensionRuntimeHealth, formatHealthFailure } = await import('
|
|
595
|
+
const { checkExtensionRuntimeHealth, formatHealthFailure } = await import('./adapters/extension/runtime.ts');
|
|
600
596
|
const report = await checkExtensionRuntimeHealth(target, cdpPort);
|
|
601
597
|
if (optionFlag(options, 'json')) console.log(JSON.stringify(report, null, 2));
|
|
602
598
|
else if (report.status === 'PASS') console.log(`PASS extension runtime cdp=${cdpPort} target=${report.targetUrl}`);
|
|
@@ -645,7 +641,7 @@ async function handleRuntimeLaunch({ options }: ParsedArgs): Promise<number> {
|
|
|
645
641
|
cdpPort,
|
|
646
642
|
artifactsDir,
|
|
647
643
|
reason: 'harness_live_script_missing',
|
|
648
|
-
fix: `Run
|
|
644
|
+
fix: `Run mm-harness install --adapter extension --target ${shellQuote(target)}, then rerun: ${runtimeLaunchCommand(target, cdpPort, chromeUserDataDir)}`,
|
|
649
645
|
command,
|
|
650
646
|
});
|
|
651
647
|
printRuntimeLaunchReport(report, optionFlag(options, 'json'));
|
|
@@ -710,7 +706,7 @@ async function handleRuntimeLaunch({ options }: ParsedArgs): Promise<number> {
|
|
|
710
706
|
}
|
|
711
707
|
|
|
712
708
|
function runtimeLaunchCommand(target: string, cdpPort: number, chromeUserDataDir?: string, startWatch = false): string {
|
|
713
|
-
const base = `
|
|
709
|
+
const base = `mm-harness runtime-launch --adapter extension --target ${shellQuote(target)} --cdp-port ${cdpPort}`;
|
|
714
710
|
const withMode = startWatch ? `${base} --start-watch` : base;
|
|
715
711
|
return chromeUserDataDir ? `${withMode} --chrome-user-data-dir ${shellQuote(chromeUserDataDir)}` : withMode;
|
|
716
712
|
}
|
|
@@ -828,7 +824,7 @@ async function handleEnsureReady({ options }: ParsedArgs): Promise<number> {
|
|
|
828
824
|
// 5 validation failure (run, run --plan, call — adapter-aware validation errors).
|
|
829
825
|
const EXIT = { ok: 0, runtime: 1, usage: 2, infra: 3, bounded: 4, validation: 5 } as const;
|
|
830
826
|
|
|
831
|
-
// Typed exit-code error: carries exitCode so both the global catch (
|
|
827
|
+
// Typed exit-code error: carries exitCode so both the global catch (mm-harness bin)
|
|
832
828
|
// and the mm-harness delegate() wrapper classify the error correctly rather than always
|
|
833
829
|
// returning 1. Usage errors (bad args / unsupported flags) carry EXIT.usage (2);
|
|
834
830
|
// validation errors carry EXIT.validation (5). Never throw a plain new Error() for
|
|
@@ -853,9 +849,7 @@ function resolveAdapter(options: CliOptions): { adapter: MetaMaskRecipeAdapter;
|
|
|
853
849
|
const explicit = optionString(options, 'adapter') ?? optionString(options, 'platform');
|
|
854
850
|
const adapter = explicit ?? detectAdapter(target);
|
|
855
851
|
if (!adapter) {
|
|
856
|
-
throw usageError(
|
|
857
|
-
`could not detect the MetaMask repo type for ${target}\n Next: pass --adapter mobile|extension|core`,
|
|
858
|
-
);
|
|
852
|
+
throw usageError(`could not detect the MetaMask repo type for ${target}\n Next: ${ADAPTER_DETECT_NEXT}`);
|
|
859
853
|
}
|
|
860
854
|
try {
|
|
861
855
|
assertAdapter(adapter);
|
|
@@ -867,20 +861,24 @@ function resolveAdapter(options: CliOptions): { adapter: MetaMaskRecipeAdapter;
|
|
|
867
861
|
|
|
868
862
|
// Adapter-aware recipe validation: schema (validateRecipeDocument) + action
|
|
869
863
|
// existence/platform against the adapter's manifest (validateRecipeWithManifest).
|
|
870
|
-
//
|
|
871
|
-
//
|
|
872
|
-
//
|
|
873
|
-
// `externalFlowIds` sourced from resolveRecipeLibrarySources, which lands with
|
|
874
|
-
// @farmslot/recipe-harness >= 0.3.3 (pending publish). Until then, self-contained
|
|
875
|
-
// recipes (all in-repo recipes + every one-node `call` recipe) validate fully;
|
|
876
|
-
// library-ref recipes would surface their refs here. Extends when 0.3.3 lands.
|
|
864
|
+
// When librarySources are provided (resolved from --library / personal / team
|
|
865
|
+
// tiers), external flow IDs from those sources are declared so `call.ref` nodes
|
|
866
|
+
// targeting library-defined flows pass schema validation.
|
|
877
867
|
async function validateRecipeAdapterAware(
|
|
878
868
|
recipe: unknown,
|
|
879
869
|
manifest: RecipeActionManifestDocument,
|
|
870
|
+
librarySources?: MetaMaskLibrarySource[],
|
|
880
871
|
): Promise<RecipeValidationResult> {
|
|
881
872
|
const { validateRecipeDocument, validateRecipeWithManifest } = await importRecipeProtocol();
|
|
882
|
-
|
|
883
|
-
|
|
873
|
+
let externalFlowIds: ReadonlySet<string> | undefined;
|
|
874
|
+
if (librarySources && librarySources.length > 0) {
|
|
875
|
+
const harness = await importRecipeHarness();
|
|
876
|
+
const resolution = await harness.loadRecipeLibraries(librarySources);
|
|
877
|
+
externalFlowIds = new Set(resolution.flows.keys());
|
|
878
|
+
}
|
|
879
|
+
const validationOptions = externalFlowIds !== undefined ? { externalFlowIds } : undefined;
|
|
880
|
+
const schema = validateRecipeDocument(recipe, validationOptions);
|
|
881
|
+
const withManifest = validateRecipeWithManifest(recipe, manifest, validationOptions);
|
|
884
882
|
const findings = [...schema.findings, ...withManifest.findings];
|
|
885
883
|
const errors = findings.filter((finding) => finding.severity === 'error').length;
|
|
886
884
|
const warnings = findings.length - errors;
|
|
@@ -905,9 +903,10 @@ function countRecipeNodes(recipe: unknown): number | undefined {
|
|
|
905
903
|
// Static, adapter-aware recipe validation shared by `run --plan` and the `run`
|
|
906
904
|
// execute path so both "validate first" the same way: read the file (missing /
|
|
907
905
|
// unparseable → usage error, nothing to validate), check the manifest, then run
|
|
908
|
-
// the adapter-aware schema + action-existence validation.
|
|
909
|
-
//
|
|
910
|
-
// log — safe to call before the
|
|
906
|
+
// the adapter-aware schema + action-existence validation. Loads library flow IDs
|
|
907
|
+
// from --library (so `call.ref` nodes to external flows resolve correctly), but
|
|
908
|
+
// never emits the engine's "Recipe libraries: …" log — safe to call before the
|
|
909
|
+
// machine-contract JSON is written.
|
|
911
910
|
interface RunRecipeStaticValidation {
|
|
912
911
|
recipe: unknown;
|
|
913
912
|
recipeFile: string;
|
|
@@ -958,8 +957,10 @@ async function validateRunRecipeStatic(
|
|
|
958
957
|
}
|
|
959
958
|
|
|
960
959
|
// validate.schema + validate.actions (static) — adapter-aware recipe validation.
|
|
960
|
+
// Library sources are resolved here so external `call.ref` flows validate correctly.
|
|
961
|
+
const librarySources = await resolveMetaMaskLibrarySources(optionString(options, 'library'));
|
|
961
962
|
const validation = manifestOk
|
|
962
|
-
? await validateRecipeAdapterAware(recipe, manifest)
|
|
963
|
+
? await validateRecipeAdapterAware(recipe, manifest, librarySources)
|
|
963
964
|
: { status: 'invalid' as const, findings: [], summary: { errors: 1, warnings: 0 } };
|
|
964
965
|
findings.push(...validation.findings);
|
|
965
966
|
|
|
@@ -1184,7 +1185,7 @@ async function handleCall(argv: string[]): Promise<number> {
|
|
|
1184
1185
|
heal,
|
|
1185
1186
|
state,
|
|
1186
1187
|
);
|
|
1187
|
-
if (violation !== null) return emitHealViolation(json, 'call', result, violation, state);
|
|
1188
|
+
if (violation !== null) return emitHealViolation(json, 'call', result, violation, state, adapter);
|
|
1188
1189
|
|
|
1189
1190
|
if (json) {
|
|
1190
1191
|
console.log(
|
|
@@ -1286,7 +1287,7 @@ function synthesizeOneNodeRecipe(action: string, args: Record<string, string>):
|
|
|
1286
1287
|
|
|
1287
1288
|
// Reusable one-node engine path (the same machinery `call` uses), exposed so
|
|
1288
1289
|
// `fixtures set` can apply the canonical wallet fixture through the real engine on
|
|
1289
|
-
// the extension (which has no standalone
|
|
1290
|
+
// the extension (which has no standalone shell set arm).
|
|
1290
1291
|
async function runOneNode(
|
|
1291
1292
|
adapter: MetaMaskRecipeAdapter,
|
|
1292
1293
|
action: string,
|
|
@@ -1520,7 +1521,7 @@ async function handleRun({ positional, options }: ParsedArgs): Promise<number> {
|
|
|
1520
1521
|
heal,
|
|
1521
1522
|
state,
|
|
1522
1523
|
);
|
|
1523
|
-
if (violation !== null) return emitHealViolation(json, 'run', result, violation, state);
|
|
1524
|
+
if (violation !== null) return emitHealViolation(json, 'run', result, violation, state, adapter);
|
|
1524
1525
|
const exitCode = result.status === 'pass' ? EXIT.ok : EXIT.runtime;
|
|
1525
1526
|
if (json) {
|
|
1526
1527
|
// mm-harness envelope (matches launch/verify/doctor): the engine's result is
|
|
@@ -1619,7 +1620,14 @@ function emitHealViolation(
|
|
|
1619
1620
|
result: RecipeRunResult,
|
|
1620
1621
|
violation: HealBoundViolation,
|
|
1621
1622
|
state: HealState,
|
|
1623
|
+
adapter?: MetaMaskRecipeAdapter,
|
|
1622
1624
|
): number {
|
|
1625
|
+
// core is headless: `fixtures set` is blocked. Teach the env-var / recipe-node
|
|
1626
|
+
// path instead so the user has a reachable next step.
|
|
1627
|
+
const userAction =
|
|
1628
|
+
adapter === 'core' && violation.code === 'WALLET_STATE_REQUIRED'
|
|
1629
|
+
? 'set MM_TEST_ACCOUNT_ADDRESS=<0x…> in env, or add "account": "<0x…>" to the node block in the recipe'
|
|
1630
|
+
: violation.userAction;
|
|
1623
1631
|
if (json) {
|
|
1624
1632
|
console.log(
|
|
1625
1633
|
JSON.stringify(
|
|
@@ -1639,7 +1647,7 @@ function emitHealViolation(
|
|
|
1639
1647
|
code: violation.code,
|
|
1640
1648
|
message: violation.message,
|
|
1641
1649
|
retryable: false,
|
|
1642
|
-
userAction:
|
|
1650
|
+
userAction: userAction ?? null,
|
|
1643
1651
|
originalError: violation.originalError ?? null,
|
|
1644
1652
|
},
|
|
1645
1653
|
},
|
|
@@ -1651,7 +1659,7 @@ function emitHealViolation(
|
|
|
1651
1659
|
console.error(
|
|
1652
1660
|
`✗ mm-harness ${command}: ${violation.message}` +
|
|
1653
1661
|
(violation.originalError ? `\n --- original failure ---\n${violation.originalError}` : '') +
|
|
1654
|
-
(
|
|
1662
|
+
(userAction ? `\n Next: ${userAction}` : ''),
|
|
1655
1663
|
);
|
|
1656
1664
|
}
|
|
1657
1665
|
return violation.exitCode;
|
|
@@ -1792,7 +1800,7 @@ export async function main(argv: string[]): Promise<number> {
|
|
|
1792
1800
|
}
|
|
1793
1801
|
return code;
|
|
1794
1802
|
}
|
|
1795
|
-
// launch/logs/debug/fixtures compose
|
|
1803
|
+
// launch/logs/debug/fixtures compose adapter scripts directly and own policy,
|
|
1796
1804
|
// healing, teaching, and the --json contract.
|
|
1797
1805
|
if (command === 'launch') return handleLaunch(argv.slice(1));
|
|
1798
1806
|
if (command === 'logs') return handleLogs(argv.slice(1));
|
|
@@ -1803,8 +1811,8 @@ export async function main(argv: string[]): Promise<number> {
|
|
|
1803
1811
|
return handler(parseArgs(argv.slice(1), command));
|
|
1804
1812
|
}
|
|
1805
1813
|
|
|
1806
|
-
// Auto-run only when this file IS the process entry (
|
|
1807
|
-
//
|
|
1814
|
+
// Auto-run only when this file IS the process entry (bin/mm-harness execs it
|
|
1815
|
+
// directly). The commander front (`src/mm-harness-cli.ts`) sets this flag
|
|
1808
1816
|
// before importing so it can reuse `main` without triggering a second dispatch.
|
|
1809
1817
|
if (!(globalThis as Record<string, unknown>).__MM_HARNESS_WRAPPER__) {
|
|
1810
1818
|
try {
|
|
@@ -0,0 +1,63 @@
|
|
|
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 { ADAPTER_DETECT_NEXT, EXIT, flag, parseFlags, resolveAdapter, spawnScript, targetOf, usageOut } from './shared.ts';
|
|
9
|
+
|
|
10
|
+
const DEBUG_BOOLEANS = new Set(['worker', 'devMenu', 'json']);
|
|
11
|
+
|
|
12
|
+
export async function handleDebug(argv: string[]): Promise<number> {
|
|
13
|
+
const { options } = parseFlags(argv, DEBUG_BOOLEANS);
|
|
14
|
+
const json = flag(options, 'json');
|
|
15
|
+
const target = targetOf(options);
|
|
16
|
+
const adapter = resolveAdapter(options, target);
|
|
17
|
+
|
|
18
|
+
if (!adapter) return usageOut(json, 'debug', `could not detect the MetaMask repo type for ${target}`, ADAPTER_DETECT_NEXT);
|
|
19
|
+
if (adapter === 'core') return usageOut(json, 'debug', 'core is headless; there is no debug console.', 'mm-harness verify');
|
|
20
|
+
|
|
21
|
+
const worker = flag(options, 'worker');
|
|
22
|
+
const devMenu = flag(options, 'devMenu');
|
|
23
|
+
if (adapter === 'mobile' && worker) {
|
|
24
|
+
return usageOut(
|
|
25
|
+
json,
|
|
26
|
+
'debug',
|
|
27
|
+
'--worker is extension-only (service-worker DevTools). Use --dev-menu on mobile.',
|
|
28
|
+
'mm-harness debug --dev-menu',
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
if (adapter === 'extension' && devMenu) {
|
|
32
|
+
return usageOut(
|
|
33
|
+
json,
|
|
34
|
+
'debug',
|
|
35
|
+
'--dev-menu is mobile-only (RN developer menu). Use --worker on the extension.',
|
|
36
|
+
'mm-harness debug --worker',
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const openDebug = path.join(runnerDir, 'adapters/shared/open-debug.mjs');
|
|
41
|
+
const debugArgs: string[] = ['--adapter', adapter];
|
|
42
|
+
|
|
43
|
+
if (adapter === 'extension') {
|
|
44
|
+
if (process.env.CDP_PORT) debugArgs.push('--cdp-port', process.env.CDP_PORT);
|
|
45
|
+
debugArgs.push('--target', worker ? 'worker' : 'page');
|
|
46
|
+
} else {
|
|
47
|
+
if (process.env.WATCHER_PORT) debugArgs.push('--port', process.env.WATCHER_PORT);
|
|
48
|
+
debugArgs.push('--action', devMenu ? 'dev-menu' : 'debug');
|
|
49
|
+
}
|
|
50
|
+
if (json) debugArgs.push('--json');
|
|
51
|
+
|
|
52
|
+
const result = spawnScript(process.execPath, [openDebug, ...debugArgs], target, json);
|
|
53
|
+
if (json) {
|
|
54
|
+
console.log(
|
|
55
|
+
JSON.stringify(
|
|
56
|
+
{ schemaVersion: 1, command: 'debug', adapter, mode: worker ? 'worker' : devMenu ? 'dev-menu' : 'default', exitCode: result.status === 0 ? EXIT.ok : EXIT.runtime },
|
|
57
|
+
null,
|
|
58
|
+
2,
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return result.status === 0 ? EXIT.ok : EXIT.runtime;
|
|
63
|
+
}
|