@deeeed/metamask-harness 0.92.21 → 0.92.23

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.
@@ -1,308 +1,8 @@
1
- import { execFileSync } from "node:child_process";
2
1
  import fs from "node:fs";
3
2
  import path from "node:path";
4
- import { featureFlagReport } from "../feature-flags.js";
5
- import { adapterPluginChecks, color, acquireCheckoutLock, contextAdapter, resolveRuntimeContextPath, ensureOverlay, newHealState, recipeRunning, adapterDetectNext, checkoutBusyOut, EXIT, usageOut, actionManifestPathOption, applyRuntimeDirOption, optionFlag, optionString, shellQuote, spawnScriptStreaming, doctorReady, renderDoctorRecorder, targetPath } from "@farmslot/recipe-cli/harness";
6
- import { collectCheckoutView, renderCheckoutView } from "../checkout-view.js";
7
- import { createDoctorReport, fixtureSummary, requiredDoctorCheckSummary } from "../doctor.js";
8
- import { assertAdapter, runnerDir } from "../paths.js";
9
- import { getAdapterSurface } from "../adapters/surface.js";
10
- import { loadActionManifest, validateManifest } from "../manifest.js";
11
- import { applyDeviceTargeting } from "./device-target.js";
12
- import { farmslotReadyIndicator } from "./farmslot-ready.js";
13
- import { updateStatus } from "./update.js";
14
- import { ensureRuntimeContext } from "../runtime-context.js";
15
- function applyDoctorRuntimePorts(options) {
16
- const cdpPort = optionString(options, "cdpPort");
17
- if (cdpPort) {
18
- process.env.CDP_PORT = cdpPort;
19
- process.env.RECIPE_CDP_PORT = cdpPort;
20
- }
21
- const watcherPort = optionString(options, "watcherPort") ?? optionString(options, "port");
22
- if (watcherPort) {
23
- process.env.WATCHER_PORT = watcherPort;
24
- process.env.METRO_PORT = watcherPort;
25
- process.env.RECIPE_WATCHER_PORT = watcherPort;
26
- }
27
- }
28
- async function handleDoctor({ options }) {
29
- applyRuntimeDirOption(options);
30
- const target = targetPath(options);
31
- const json = optionFlag(options, "json");
32
- const printReady = optionFlag(options, "printReady");
33
- const expectLive = optionFlag(options, "expectLive") || printReady;
34
- const allDevices = optionFlag(options, "allDevices");
35
- const platformOption = optionString(options, "platform");
36
- const adapter = contextAdapter(target);
37
- if (!adapter) {
38
- return usageOut(json, "doctor", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
39
- }
40
- assertAdapter(adapter);
41
- const { readiness } = getAdapterSurface(adapter);
42
- if (!fs.existsSync(target)) {
43
- return usageOut(
44
- json,
45
- "doctor",
46
- `target does not exist: ${target}`,
47
- "pass --target <metamask-checkout> pointing to an existing checkout"
48
- );
49
- }
50
- if (printReady && json) {
51
- return usageOut(
52
- json,
53
- "doctor",
54
- "--print-ready owns stdout for Farmslot health_check; drop --json (use --expect-live --json for the doctor envelope)",
55
- "mm-harness doctor --print-ready --adapter <adapter> --target <path>"
56
- );
57
- }
58
- const actionManifestPath = actionManifestPathOption(options, adapter);
59
- const manifest = loadActionManifest(adapter, optionString(options, "actionManifest"));
60
- const manifestValidation = await validateManifest(manifest);
61
- if (optionFlag(options, "fix")) {
62
- const surface = getAdapterSurface(adapter);
63
- surface.resolveSlotPorts(target);
64
- const dtResult = applyDeviceTargeting("doctor", adapter, options, { gate: false, rerun: "" });
65
- if ("code" in dtResult) {
66
- return usageOut(json, "doctor", dtResult.message, dtResult.userAction);
67
- }
68
- applyDoctorRuntimePorts(options);
69
- const lock = acquireCheckoutLock(target, "doctor-fix");
70
- if ("message" in lock) {
71
- return checkoutBusyOut(json, "doctor", lock.message, lock.path);
72
- }
73
- let fixed;
74
- let failed;
75
- try {
76
- ({ fixed, failed } = await runDoctorFix(adapter, target, manifestValidation, json));
77
- } finally {
78
- lock.release();
79
- }
80
- const result2 = createDoctorReport(adapter, target, manifestValidation, actionManifestPath);
81
- let runtime2;
82
- let runtimeProbeError2;
83
- try {
84
- runtime2 = await surface.runtimeStatus(target);
85
- } catch (error2) {
86
- runtimeProbeError2 = error2 instanceof Error ? error2.message : String(error2);
87
- }
88
- const recorder2 = runtime2?.decision === "ready" ? await readiness.recorder?.() : void 0;
89
- const ready2 = doctorReady(runtime2, recorder2);
90
- const block = readiness.runtimeBlock?.(target, runtime2);
91
- if (block) failed.push(block.id);
92
- if (recorder2?.status === "fail") failed.push(recorder2.id);
93
- const nextActions = doctorFixNextActions(failed, result2.fixture, adapter, target, block);
94
- if (recorder2?.status === "fail" && recorder2.userAction) nextActions.push(recorder2.userAction);
95
- if (failed.length === 0 && runtime2?.decision !== "ready" && runtime2?.nextAction) nextActions.push(runtime2.nextAction);
96
- const status = result2.status === "pass" && failed.length === 0 ? "pass" : "fail";
97
- const retryDoctor = `mm-harness doctor --fix --adapter ${adapter} --target ${shellQuote(target)} --json`;
98
- const fixUserAction = failed.includes("wallet-fixture") ? `choose one wallet fixture source from nextActions, run it, then retry: ${retryDoctor}` : nextActions[0] ?? retryDoctor;
99
- const error = status === "fail" ? {
100
- code: "DOCTOR_FIX_INCOMPLETE",
101
- message: "doctor --fix could not make every required check pass",
102
- userAction: fixUserAction
103
- } : void 0;
104
- if (json) console.log(JSON.stringify({ ...result2, status, fixed, failed, ready: ready2, runtime: runtime2, ...recorder2 ? { recorder: recorder2 } : {}, ...runtimeProbeError2 ? { runtimeProbeError: runtimeProbeError2 } : {}, nextActions, ...error ? { error } : {} }, null, 2));
105
- else {
106
- console.log(`${status} ${adapter} ${result2.compatibilityMode} ready=${ready2} manifest=${actionManifestPath} fixed=[${fixed.join(",")}] failed=[${failed.join(",")}]`);
107
- if (runtime2) {
108
- console.log(`runtime: decision=${runtime2.decision}${runtime2.reasonCode ? ` (${runtime2.reasonCode})` : ""}`);
109
- for (const reason of runtime2.reasons) console.log(` ${reason}`);
110
- } else if (runtimeProbeError2) {
111
- console.log(`runtime probe failed: ${runtimeProbeError2}`);
112
- }
113
- renderDoctorRecorder(recorder2);
114
- for (const action of nextActions) console.error(` Next: ${action}`);
115
- }
116
- return status === "pass" ? 0 : 1;
117
- }
118
- const result = createDoctorReport(
119
- adapter,
120
- target,
121
- manifestValidation,
122
- actionManifestPath,
123
- platformOption
124
- );
125
- const view = collectCheckoutView(target, adapter);
126
- const missingRequiredTool = result.checks.find(
127
- (check) => check.required && check.status === "fail" && check.id.startsWith("device-tool-") && check.userAction
128
- );
129
- if (missingRequiredTool) {
130
- const error = {
131
- code: "DOCTOR_CHECKS_FAILED",
132
- message: missingRequiredTool.message,
133
- userAction: missingRequiredTool.userAction
134
- };
135
- if (json) {
136
- console.log(JSON.stringify({ ...result, ready: false, error }, null, 2));
137
- } else {
138
- console.error(`\u2717 doctor: ${error.message}
139
- Next: ${error.userAction}`);
140
- }
141
- return EXIT.runtime;
142
- }
143
- let runtime;
144
- let runtimeProbeError;
145
- try {
146
- const surface = getAdapterSurface(adapter);
147
- surface.resolveSlotPorts(target);
148
- const dtResult = applyDeviceTargeting("doctor", adapter, options, { gate: false, rerun: "" });
149
- if ("code" in dtResult) {
150
- if (json) console.log(JSON.stringify({ schemaVersion: 1, command: "doctor", adapter, target, error: { code: dtResult.code, message: dtResult.message, userAction: dtResult.userAction } }, null, 2));
151
- else console.error(`\u2717 doctor: ${dtResult.message}
152
- Next: ${dtResult.userAction}`);
153
- return EXIT.usage;
154
- }
155
- applyDoctorRuntimePorts(options);
156
- runtime = await surface.runtimeStatus(target);
157
- } catch (error) {
158
- runtimeProbeError = error instanceof Error ? error.message : String(error);
159
- }
160
- const runtimeCheck = doctorRuntimeCheck(runtime, runtimeProbeError, expectLive);
161
- const recorder = runtime?.decision === "ready" ? await readiness.recorder?.() : void 0;
162
- const checks = [
163
- ...result.checks,
164
- runtimeCheck,
165
- ...await readiness.liveChecks?.(target) ?? [],
166
- ...recorder ? [recorder] : [],
167
- ...await platformDoctorChecks(adapter, target),
168
- // Which library plugin code this process loaded: library, module and digest.
169
- ...adapterPluginChecks()
170
- ];
171
- const requiredChecks = requiredDoctorCheckSummary(checks);
172
- const doctorResult = {
173
- ...result,
174
- status: requiredChecks.status,
175
- checks,
176
- requiredChecks
177
- };
178
- const orphanMetros = readiness.orphanDevServers?.(target, process.env.WATCHER_PORT) ?? [];
179
- const capture = captureHealth(readiness.captureProviders);
180
- const deviceSource = await readiness.devices?.();
181
- const deviceView = deviceSource ? deviceSource.view(allDevices) : null;
182
- const liveView = deviceSource && deviceView ? await deviceSource.live(target, deviceView) : null;
183
- const devices = liveView?.devicesWithLive ?? deviceView?.devices ?? [];
184
- const additionalReachableDevices = liveView?.additionalReachableDevices ?? [];
185
- const discovery = deviceView?.deviceDiscoveryErrors.length ? { deviceDiscoveryErrors: deviceView.deviceDiscoveryErrors } : {};
186
- if (expectLive) {
187
- return emitExpectLive(
188
- adapter,
189
- target,
190
- runtime,
191
- recorder,
192
- doctorResult,
193
- orphanMetros,
194
- capture,
195
- devices,
196
- additionalReachableDevices,
197
- json,
198
- printReady,
199
- discovery
200
- );
201
- }
202
- const skills = skillsView(target);
203
- const update = updateStatus();
204
- const pinnedFlags = readiness.pinnedFlags?.(target) ?? null;
205
- const featureFlags = pinnedFlags ? featureFlagReport(pinnedFlags.overrides, pinnedFlags) : featureFlagReport(liveView?.featureFlagOverrides ?? null);
206
- const doctorUserAction = doctorResult.checks.find(
207
- (check) => check.required && check.status === "fail" && check.userAction
208
- )?.userAction ?? `mm-harness doctor --fix --adapter ${adapter} --target ${shellQuote(target)} --json`;
209
- const doctorError = doctorResult.status === "fail" ? { code: "DOCTOR_CHECKS_FAILED", message: "one or more required doctor checks failed", userAction: doctorUserAction } : void 0;
210
- const next = doctorError?.userAction ?? discovery.deviceDiscoveryErrors?.[0]?.userAction ?? (runtime?.decision === "ready" ? void 0 : runtime?.nextAction);
211
- const ready = doctorReady(runtime, recorder);
212
- if (json) console.log(JSON.stringify({ ...doctorResult, ready, runtime, ...recorder ? { recorder } : {}, view, orphanMetros, capture, skills, update, featureFlags, devices, additionalReachableDevices, ...discovery, ...next ? { next } : {}, ...doctorError ? { error: doctorError } : {} }, null, 2));
213
- else {
214
- const out = (style, text) => color(style, text, { stream: process.stdout });
215
- const stateStyle = (value, good) => value === good ? "ok" : "warn";
216
- console.log(`${out(doctorResult.status === "pass" ? "ok" : "err", doctorResult.status)} ${out("bold", adapter)} ${doctorResult.compatibilityMode} ${out("dim", `manifest=${actionManifestPath}`)}`);
217
- console.log(
218
- `${out("label", "harness:")} ${doctorResult.runner.packageName}@${doctorResult.runner.version} ${out("accent", doctorResult.runner.installKind)} ${out("dim", `executable=${doctorResult.runner.executablePath}`)}`
219
- );
220
- if (runtime) {
221
- const provisionedDepsPending = runtime.reasonCode === "app-installed-deps-pending";
222
- const decisionStyle = provisionedDepsPending ? "info" : runtime.decision === "ready" ? "ok" : runtime.decision === "blocked" ? "err" : "warn";
223
- const depsStyle = provisionedDepsPending ? "info" : stateStyle(runtime.deps, "current");
224
- const devServerStyle = provisionedDepsPending ? "info" : void 0;
225
- const devServer = runtime.devServer ? ` ${runtime.devServer.label}=${out(devServerStyle ?? stateStyle(runtime.devServer.status, "up"), runtime.devServer.status)}` : "";
226
- console.log(
227
- `${out("label", "runtime:")} decision=${out(decisionStyle, runtime.decision)}${runtime.reasonCode ? ` ${out("dim", `(${runtime.reasonCode})`)}` : ""} deps=${out(depsStyle, runtime.deps ?? "unknown")}${devServer}`
228
- );
229
- for (const reason of runtime.reasons) console.log(` ${out("dim", reason)}`);
230
- } else if (runtimeProbeError) {
231
- console.log(`${out("err", "runtime probe failed:")} ${out("dim", runtimeProbeError)}`);
232
- }
233
- renderDoctorRecorder(recorder, out);
234
- console.log(renderCheckoutView(view));
235
- console.log(`${out("label", "feature flags:")} ${out(
236
- featureFlags.error || (featureFlags.overrideCount ?? 0) > 0 ? "warn" : "dim",
237
- featureFlags.summary.replace(/^feature flags: /u, "")
238
- )}`);
239
- for (const line of readiness.lines?.(target) ?? []) console.log(line);
240
- if (orphanMetros.length > 0) {
241
- console.log(
242
- `${out("warn", "orphan Metro:")} ${orphanMetros.length} leaked bundler(s) for this checkout (pids ${orphanMetros.join(", ")})`
243
- );
244
- console.log(` ${out("dim", "Next: mm-harness stop # reaps every bundler this checkout leaked")}`);
245
- }
246
- if (capture) renderCaptureHealth(capture, out);
247
- renderSkillsView(skills, out);
248
- renderUpdateStatus(update, out);
249
- if (deviceSource) {
250
- if (deviceView) deviceSource.renderList(deviceView, out);
251
- if (additionalReachableDevices.length > 0) deviceSource.renderAdditional(additionalReachableDevices, out);
252
- if (liveView) deviceSource.renderLive(deviceView?.devices ?? [], liveView.liveMap, out);
253
- }
254
- if (next) console.log(` ${out("dim", `Next: ${next}`)}`);
255
- }
256
- return doctorResult.status === "pass" ? 0 : 1;
257
- }
258
- import { doctorReady as doctorReady2 } from "@farmslot/recipe-cli/harness";
259
- async function platformDoctorChecks(adapter, target) {
260
- try {
261
- return await getAdapterSurface(adapter).doctor?.(target) ?? [];
262
- } catch (error) {
263
- return [{
264
- id: `adapter-plugin:${adapter}:doctor`,
265
- status: "fail",
266
- required: true,
267
- message: `${adapter}'s doctor checks failed to run.`,
268
- detail: error instanceof Error ? error.message : String(error),
269
- userAction: `fix the doctor() of the ${adapter} adapter, then rerun mm-harness doctor --adapter ${adapter}`
270
- }];
271
- }
272
- }
273
- function doctorRuntimeCheck(runtime, error, expectLive) {
274
- if (error) {
275
- return {
276
- id: "runtime",
277
- status: "fail",
278
- required: true,
279
- message: "Runtime readiness probe failed.",
280
- detail: error
281
- };
282
- }
283
- const ready = runtime?.decision === "ready";
284
- return {
285
- id: "runtime",
286
- status: ready ? "pass" : "fail",
287
- required: expectLive,
288
- message: ready ? "Runtime is ready." : `Runtime is not ready${runtime?.reasonCode ? ` (${runtime.reasonCode})` : "."}`,
289
- detail: runtime?.reasons.join(" | ") || "Runtime readiness probe returned no result."
290
- };
291
- }
292
- function doctorFixNextActions(failed, fixture, adapter, target, block) {
293
- const actions = [];
294
- const executable = process.env.MM_HARNESS_EXECUTABLE ? shellQuote(process.env.MM_HARNESS_EXECUTABLE) : "mm-harness";
295
- const scope = `--adapter ${adapter} --target ${shellQuote(target)}`;
296
- actions.push(...doctorFixtureNextActions(failed, fixture, scope, executable));
297
- if (failed.includes("runtime-context")) {
298
- actions.push(
299
- `inspect ${shellQuote(resolveRuntimeContextPath(target))}, then retry ${executable} doctor --fix ${scope}`
300
- );
301
- }
302
- if (failed.includes("overlay")) actions.push(`${executable} install ${scope}`);
303
- if (block?.userAction && failed.includes(block.id)) actions.push(block.userAction);
304
- return actions;
305
- }
3
+ import { shellQuote, spawnScriptStreaming } from "@farmslot/recipe-cli/harness";
4
+ import { fixtureSummary } from "../doctor.js";
5
+ import { runnerDir } from "../paths.js";
306
6
  function doctorFixtureNextActions(failed, fixture, scope, executable = process.env.MM_HARNESS_EXECUTABLE ? shellQuote(process.env.MM_HARNESS_EXECUTABLE) : "mm-harness") {
307
7
  const actions = [];
308
8
  if (failed.includes("wallet-fixture")) {
@@ -312,91 +12,6 @@ function doctorFixtureNextActions(failed, fixture, scope, executable = process.e
312
12
  }
313
13
  return actions;
314
14
  }
315
- function emitExpectLiveVerdict(adapter, target, runtime, verdict, recorder) {
316
- const out = (style, text) => color(style, text, { stream: process.stderr });
317
- const detail = runtime ? `${runtime.decision}${runtime.reasonCode ? ` (${runtime.reasonCode})` : ""}` : "runtime probe unavailable";
318
- console.error(`${out("err", verdict)} ${out("bold", adapter)} ${detail} ${out("dim", target)}`);
319
- for (const reason of runtime?.reasons ?? []) console.error(` ${out("dim", reason)}`);
320
- if (recorder?.status === "fail") {
321
- console.error(` ${out("err", "recorder:")} ${recorder.message}${recorder.detail ? ` ${out("dim", recorder.detail)}` : ""}`);
322
- console.error(` Next: ${recorder.userAction}`);
323
- return;
324
- }
325
- console.error(` Next: ${runtime?.nextAction ?? getAdapterSurface(adapter).hints.runtimeProbeRecovery(target)}`);
326
- }
327
- function emitExpectLive(adapter, target, runtime, recorder, result, orphanMetros, capture, devices, additionalReachableDevices, json, printReady, discovery) {
328
- const live = runtime?.decision === "ready";
329
- const ready = doctorReady(runtime, recorder);
330
- if (printReady) {
331
- if (ready) {
332
- const indicator = farmslotReadyIndicator(adapter, devices);
333
- if (indicator) {
334
- console.log(indicator);
335
- return EXIT.ok;
336
- }
337
- emitExpectLiveVerdict(adapter, target, runtime, "not-ready");
338
- return EXIT.runtime;
339
- }
340
- emitExpectLiveVerdict(adapter, target, runtime, live ? "not-ready" : "not-live", recorder);
341
- return EXIT.runtime;
342
- }
343
- if (json) {
344
- const userAction = runtime?.nextAction ?? getAdapterSurface(adapter).hints.runtimeProbeRecovery(target);
345
- const error = !live ? { code: "RUNTIME_NOT_LIVE", message: `${adapter} runtime is not live`, userAction } : !ready ? { code: "RECORDER_UNAVAILABLE", message: recorder.message, userAction: recorder.userAction } : void 0;
346
- console.log(JSON.stringify({ ...result, ready, runtime, ...recorder ? { recorder } : {}, orphanMetros, capture, devices, additionalReachableDevices, ...discovery, ...error ? { error } : {} }, null, 2));
347
- return ready ? EXIT.ok : EXIT.runtime;
348
- }
349
- const out = (style, text) => color(style, text, { stream: process.stdout });
350
- if (ready) {
351
- console.log(`${out("ok", "live")} ${out("bold", adapter)} runtime ready`);
352
- return EXIT.ok;
353
- }
354
- emitExpectLiveVerdict(adapter, target, runtime, live ? "not-ready" : "not-live", recorder);
355
- return EXIT.runtime;
356
- }
357
- function captureHealth(providers) {
358
- if (!providers) return null;
359
- const fallback = [...providers];
360
- const helper = captureHelperHealth();
361
- if (!helper) {
362
- return {
363
- status: "fallback",
364
- failing: [],
365
- screenshots: { available: true, providers: fallback },
366
- recording: { available: false, provider: null }
367
- };
368
- }
369
- return {
370
- status: helper.status,
371
- failing: helper.failing,
372
- screenshots: { available: true, providers: ["capture-helper", ...fallback] },
373
- recording: { available: helper.status === "pass", provider: helper.status === "pass" ? "capture-helper" : null }
374
- };
375
- }
376
- function captureHelperHealth() {
377
- if (process.platform !== "darwin") return null;
378
- const bin = process.env.CAPTURE_HELPER_PATH || "capture-helper";
379
- try {
380
- const out = execFileSync(bin, ["doctor", "--json"], { encoding: "utf8", timeout: 1e4, stdio: ["ignore", "pipe", "ignore"] });
381
- const parsed = JSON.parse(out);
382
- const failing = (parsed.checks ?? []).filter((c) => c.required === true && c.ok === false).map((c) => c.name ?? c.id ?? "check");
383
- return { status: parsed.ok === true && failing.length === 0 ? "pass" : "warn", failing };
384
- } catch {
385
- return null;
386
- }
387
- }
388
- function renderCaptureHealth(capture, out) {
389
- const video = capture.recording.available ? "capture-helper" : "unavailable";
390
- console.log(
391
- `${out("label", "capture:")} ${out(capture.status === "pass" ? "ok" : "warn", capture.status)} ${out("dim", `(screenshots: ${capture.screenshots.providers.join(" \u2192 ")}; video: ${video})`)}`
392
- );
393
- if (capture.status === "warn") {
394
- if (capture.failing.length > 0) console.log(` ${out("dim", `failing: ${capture.failing.join(", ")}`)}`);
395
- console.log(` ${out("dim", "Next: grant Screen Recording (System Settings \u2192 Privacy & Security \u2192 Screen Recording), or run: capture-helper doctor --open-permissions")}`);
396
- } else if (capture.status === "fallback") {
397
- console.log(` ${out("dim", "Next: screenshots work without capture-helper; install/configure capture-helper only when recipe video is required")}`);
398
- }
399
- }
400
15
  const SKILL_ROOTS = [path.join(".claude", "skills"), path.join(".agents", "skills")];
401
16
  function skillsView(target) {
402
17
  const names = /* @__PURE__ */ new Set();
@@ -432,38 +47,6 @@ function renderUpdateStatus(status, out) {
432
47
  status.updateAvailable ? `${out("label", "update:")} ${out("warn", `${status.current} \u2192 ${status.latest} available`)} ${out("dim", "(mm-harness update)")}` : status.latest && status.latest !== status.current ? `${out("label", "update:")} ${out("ok", status.current)} ${out("dim", `ahead of registry ${status.latest}`)}` : `${out("label", "update:")} ${out("ok", `${status.current} is latest`)}`
433
48
  );
434
49
  }
435
- async function runDoctorFix(adapter, target, manifestValidation, json) {
436
- const fixed = [];
437
- const failed = [];
438
- if (recipeRunning(target)) {
439
- failed.push("recipe-running");
440
- return { fixed, failed };
441
- }
442
- if (Number(manifestValidation.summary?.errors ?? 0) > 0) failed.push("manifest");
443
- try {
444
- const surface = getAdapterSurface(adapter);
445
- surface.resolveSlotPorts(target);
446
- const runtimeContext = ensureRuntimeContext(target, adapter);
447
- if (runtimeContext.created) fixed.push("runtime-context");
448
- } catch {
449
- failed.push("runtime-context");
450
- }
451
- for (const fix of getAdapterSurface(adapter).readiness.fixes ?? []) {
452
- try {
453
- if (fix.apply(target)) fixed.push(fix.id);
454
- } catch {
455
- failed.push(fix.id);
456
- }
457
- }
458
- const state = newHealState();
459
- const ensured = await ensureOverlay(adapter, target, "infra-only", state, json);
460
- if (!ensured.ok) failed.push("overlay");
461
- else if (state.mutations.length > 0) fixed.push("overlay");
462
- const fixture = await repairDoctorFixture(target, adapter, json);
463
- fixed.push(...fixture.fixed);
464
- failed.push(...fixture.failed);
465
- return { fixed, failed };
466
- }
467
50
  async function repairDoctorFixture(target, adapter, json) {
468
51
  if (fixtureSummary(target, adapter).status === "ready") return { fixed: [], failed: [] };
469
52
  const syncFixture = path.join(runnerDir, "adapters/shared/sync-wallet-fixture.sh");
@@ -474,10 +57,7 @@ async function repairDoctorFixture(target, adapter, json) {
474
57
  return fixtureSummary(target, adapter).status === "ready" ? { fixed: ["wallet-fixture"], failed: [] } : { fixed: [], failed: ["wallet-fixture"] };
475
58
  }
476
59
  export {
477
- doctorFixNextActions,
478
60
  doctorFixtureNextActions,
479
- doctorReady2 as doctorReady,
480
- handleDoctor,
481
61
  renderSkillsView,
482
62
  renderUpdateStatus,
483
63
  repairDoctorFixture,
@@ -9,11 +9,9 @@ import {
9
9
  readConfig,
10
10
  referenceHint,
11
11
  REVIEW_ADAPTERS,
12
- renderReviewChecklist,
13
12
  renderReviewHelp,
14
13
  resolveLibrary,
15
- resolveReference,
16
- defaultBaseRef
14
+ resolveReference
17
15
  } from "../review/knowledge.js";
18
16
  const EXIT_OK = 0;
19
17
  let cachedHarnessVersion;
@@ -32,16 +30,15 @@ function adapterFromOptions() {
32
30
  }
33
31
  return scope ?? "unscoped";
34
32
  }
35
- function resolveReviewContext(options, { fetch = true } = {}) {
33
+ function resolveReviewContext(options) {
36
34
  const target = targetPath(options);
37
35
  const adapter = adapterFromOptions();
38
36
  const domain = optionString(options, "domain") ?? process.env.MM_HARNESS_DOMAIN;
39
37
  const config = readConfig(configPath());
40
38
  const context = { target, adapter, ...domain ? { domain } : {} };
41
39
  if (domain) {
42
- const library = resolveLibrary(domain, { target, config, fetch });
40
+ const library = resolveLibrary(domain, { target, config });
43
41
  if (library) context.knowledge = loadDomainKnowledge(library, adapter === "unscoped" ? void 0 : adapter);
44
- else if (fetch) throw usageError(`No library found for domain "${domain}". Set RECIPE_LIBRARY_PATH="${domain}=<path>" or run: mm-harness config set libraries.${domain} <path>`);
45
42
  }
46
43
  const parity = parityAdapter(adapter);
47
44
  if (parity) {
@@ -53,7 +50,7 @@ function resolveReviewContext(options, { fetch = true } = {}) {
53
50
  }
54
51
  function handleHelpReview(argv, harnessVersion2) {
55
52
  const parsed = parseArgs(argv);
56
- const context = resolveReviewContext(parsed.options, { fetch: false });
53
+ const context = resolveReviewContext(parsed.options);
57
54
  const input = {
58
55
  adapter: context.adapter,
59
56
  harnessVersion: harnessVersion2,
@@ -70,66 +67,8 @@ function handleHelpReview(argv, harnessVersion2) {
70
67
  }
71
68
  return EXIT_OK;
72
69
  }
73
- async function handleReview(argv, version = harnessVersion()) {
74
- const parsed = parseArgs(argv);
75
- const subcommand = parsed.positional[0];
76
- if (subcommand !== "checklist") {
77
- throw usageError("Usage: mm-harness review checklist [--domain <name>] [--since <sha>] [--base <ref>] [--out <file>] [--json]");
78
- }
79
- const context = resolveReviewContext(parsed.options);
80
- const since = optionString(parsed.options, "since");
81
- const base = optionString(parsed.options, "base") ?? defaultBaseRef(context.target);
82
- const checklist = renderReviewChecklist({
83
- adapter: context.adapter,
84
- target: context.target,
85
- base,
86
- harnessVersion: version,
87
- ...since ? { since } : {},
88
- ...context.domain ? { domain: context.domain } : {},
89
- ...context.knowledge ? { knowledge: context.knowledge } : {},
90
- ...context.reference ? { reference: context.reference } : {},
91
- ...context.referenceMissing ? { referenceMissing: context.referenceMissing } : {}
92
- });
93
- const out = optionString(parsed.options, "out");
94
- if (out) {
95
- const file = path.resolve(out);
96
- fs.mkdirSync(path.dirname(file), { recursive: true });
97
- fs.writeFileSync(file, checklist);
98
- }
99
- if (optionFlag(parsed.options, "json")) {
100
- process.stdout.write(
101
- `${JSON.stringify(
102
- {
103
- command: "review",
104
- subcommand: "checklist",
105
- target: context.target,
106
- adapter: context.adapter,
107
- domain: context.domain ?? null,
108
- library: context.knowledge?.library ?? null,
109
- reference: context.reference ?? null,
110
- referenceMissing: context.referenceMissing ?? null,
111
- base,
112
- since: since ?? null,
113
- out: out ? path.resolve(out) : null,
114
- checklist
115
- },
116
- null,
117
- 2
118
- )}
119
- `
120
- );
121
- } else if (out) {
122
- process.stdout.write(`review checklist: ${path.resolve(out)}
123
- `);
124
- } else {
125
- process.stdout.write(checklist);
126
- }
127
- return EXIT_OK;
128
- }
129
70
  export {
130
71
  adapterFromOptions,
131
72
  handleHelpReview,
132
- handleReview,
133
- harnessVersion,
134
- resolveReviewContext
73
+ harnessVersion
135
74
  };
package/dist/doctor.js CHANGED
@@ -5,16 +5,6 @@ import { normalizeFeatureFlagRecord } from "./feature-flags.js";
5
5
  import { getAdapterSurface } from "./adapters/surface.js";
6
6
  import { isPin } from "./harness-pin.js";
7
7
  import { readJson } from "./paths.js";
8
- function requiredDoctorCheckSummary(checks) {
9
- const required = checks.filter((check) => check.required);
10
- const failed = required.filter((check) => check.status === "fail").map((check) => check.id);
11
- return {
12
- status: failed.length === 0 ? "pass" : "fail",
13
- total: required.length,
14
- passed: required.length - failed.length,
15
- failed
16
- };
17
- }
18
8
  function repoShape(target) {
19
9
  const exists = (rel) => fs.existsSync(path.join(target, rel));
20
10
  const packageInfo = readPackageInfo(target);
@@ -188,7 +178,6 @@ export {
188
178
  fixtureSummary,
189
179
  renderRuntimeContext,
190
180
  repoShape,
191
- requiredDoctorCheckSummary,
192
181
  runnerInstallKind,
193
182
  runnerProvenance,
194
183
  runtimeContextSummary