@deeeed/metamask-harness 0.78.0 → 0.80.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 (215) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +1 -1
  3. package/adapters/extension/ensure-browser.sh +2 -2
  4. package/adapters/extension/inject.mjs +0 -1
  5. package/adapters/extension/launch-browser.cjs +39 -613
  6. package/adapters/extension/readiness.mjs +2 -5
  7. package/adapters/extension/reattach.sh +2 -2
  8. package/adapters/extension/stamp-runtime-title.cjs +1 -1
  9. package/adapters/manifest.json +2 -34
  10. package/adapters/mobile/bridge-runtime/cdp-bridge.cjs +57 -1358
  11. package/adapters/mobile/bridge-runtime/teaching.cjs +20 -0
  12. package/adapters/mobile/inject.sh +16 -0
  13. package/adapters/mobile/launch-console-forwarder.cjs +1 -2
  14. package/adapters/mobile/open-device.sh +2 -2
  15. package/adapters/mobile/reload-app.mjs +4 -4
  16. package/adapters/mobile/reset-app-data.sh +1 -1
  17. package/adapters/mobile/start-console-forwarder.sh +3 -2
  18. package/adapters/mobile/start-metro.sh +17 -12
  19. package/adapters/mobile/wait-for-bridge.cjs +2 -2
  20. package/adapters/shared/ensure-runner-deps.sh +2 -2
  21. package/adapters/shared/harness-source-fingerprint.mjs +13 -8
  22. package/adapters/shared/open-debug.mjs +2 -2
  23. package/adapters/shared/runner-deps-ready.mjs +1 -1
  24. package/adapters/shared/sync-wallet-fixture.sh +8 -5
  25. package/adapters/terminal/cleanup.mjs +2 -1
  26. package/adapters/terminal/inject.mjs +2 -1
  27. package/adapters/terminal/lib/cdp-client.mjs +1 -1
  28. package/bin/mm-harness +9 -28
  29. package/dist/adapters/checkout-files.js +16 -0
  30. package/dist/adapters/console-capture.js +14 -1
  31. package/dist/adapters/core/actions.js +4 -3
  32. package/dist/adapters/core/overlay.js +1 -1
  33. package/dist/adapters/core/readiness.js +28 -1
  34. package/dist/adapters/core/run.js +3 -3
  35. package/dist/adapters/core/surface.js +22 -5
  36. package/dist/adapters/extension/browser-pid.js +56 -0
  37. package/dist/adapters/extension/console-capture.js +1 -1
  38. package/dist/adapters/extension/doctor-checks.js +1 -1
  39. package/dist/adapters/extension/ensure-ready.js +5 -4
  40. package/dist/adapters/extension/extension-id.js +1 -1
  41. package/dist/adapters/extension/feature-flags.js +1 -1
  42. package/dist/adapters/extension/fixtures.js +1 -2
  43. package/dist/adapters/extension/launch.js +4 -5
  44. package/dist/adapters/extension/launched-browser.js +1 -2
  45. package/dist/adapters/extension/network-observer.js +1 -1
  46. package/dist/adapters/extension/overlay.js +1 -1
  47. package/dist/adapters/extension/product-config.js +1 -1
  48. package/dist/adapters/extension/readiness.js +1 -1
  49. package/dist/adapters/extension/reload.js +1 -1
  50. package/dist/adapters/extension/run.js +24 -10
  51. package/dist/adapters/extension/runtime-decision.js +3 -2
  52. package/dist/adapters/extension/runtime.js +9 -5
  53. package/dist/adapters/extension/surface.js +20 -5
  54. package/dist/adapters/extension/verify.js +2 -2
  55. package/dist/adapters/harness-freshness.js +2 -1
  56. package/dist/adapters/mobile/android-gfxinfo-performance.js +1 -3
  57. package/dist/adapters/mobile/app-identity.js +10 -0
  58. package/dist/adapters/mobile/doctor-checks.js +1 -1
  59. package/dist/adapters/mobile/fixtures.js +1 -1
  60. package/dist/adapters/mobile/launch.js +27 -28
  61. package/dist/adapters/mobile/lifecycle.js +1 -1
  62. package/dist/adapters/mobile/metro-env.js +9 -59
  63. package/dist/adapters/mobile/performance-observer.js +1 -1
  64. package/dist/adapters/mobile/prepare-target.js +1 -1
  65. package/dist/adapters/mobile/prepare.js +4 -5
  66. package/dist/adapters/mobile/provision.js +1 -1
  67. package/dist/adapters/mobile/readiness.js +1 -1
  68. package/dist/adapters/mobile/recording-target.js +15 -0
  69. package/dist/adapters/mobile/release-artifact-state.js +1 -1
  70. package/dist/adapters/mobile/reload.js +1 -1
  71. package/dist/adapters/mobile/run.js +9 -8
  72. package/dist/adapters/mobile/runtime-decision.js +5 -7
  73. package/dist/adapters/mobile/source-freshness.js +22 -126
  74. package/dist/adapters/mobile/surface.js +31 -6
  75. package/dist/adapters/mobile/ui.js +16 -5
  76. package/dist/adapters/mobile/verify.js +2 -3
  77. package/dist/adapters/performance/cdp-trace.js +1 -1
  78. package/dist/adapters/performance/device-platform.js +1 -1
  79. package/dist/adapters/registry.js +2 -14
  80. package/dist/adapters/slot-ports.js +1 -1
  81. package/dist/adapters/surface.js +1 -0
  82. package/dist/adapters/terminal/console-capture.js +1 -1
  83. package/dist/adapters/terminal/launch.js +1 -1
  84. package/dist/adapters/terminal/run.js +25 -2
  85. package/dist/adapters/terminal/surface.js +12 -4
  86. package/dist/adapters.js +8 -4
  87. package/dist/advisor-policy.js +1 -1
  88. package/dist/checkout-view.js +1 -2
  89. package/dist/cli.js +28 -15
  90. package/dist/command-contract.js +1 -26
  91. package/dist/commands/call.js +10 -24
  92. package/dist/commands/check.js +3 -4
  93. package/dist/commands/checklist.js +1 -1
  94. package/dist/commands/completion-candidates.js +2 -10
  95. package/dist/commands/config.js +2 -2
  96. package/dist/commands/core-readiness.js +12 -7
  97. package/dist/commands/debug.js +3 -3
  98. package/dist/commands/device-target.js +5 -5
  99. package/dist/commands/doctor.js +2 -14
  100. package/dist/commands/domain.js +2 -2
  101. package/dist/commands/ensure-ready.js +1 -7
  102. package/dist/commands/fixtures.js +5 -6
  103. package/dist/commands/help.js +3 -4
  104. package/dist/commands/launch/device.js +10 -17
  105. package/dist/commands/launch/extension.js +3 -9
  106. package/dist/commands/launch/mobile.js +1 -1
  107. package/dist/commands/list-executables.js +1 -3
  108. package/dist/commands/logs.js +3 -3
  109. package/dist/commands/manifest.js +1 -12
  110. package/dist/commands/mobile-device-view.js +4 -2
  111. package/dist/commands/overlay.js +110 -0
  112. package/dist/commands/pin.js +1 -1
  113. package/dist/commands/pr-body.js +2 -2
  114. package/dist/commands/prepare.js +6 -11
  115. package/dist/commands/provision.js +3 -12
  116. package/dist/commands/recipe-advice.js +1 -2
  117. package/dist/commands/recipe-quality.js +2 -3
  118. package/dist/commands/resolve-extension.js +1 -7
  119. package/dist/commands/review.js +4 -4
  120. package/dist/commands/run-engine.js +12 -51
  121. package/dist/commands/run.js +4 -25
  122. package/dist/commands/runtime-decision.js +1 -6
  123. package/dist/commands/runtime-health.js +1 -7
  124. package/dist/commands/runtime-launch.js +1 -13
  125. package/dist/commands/self-test.js +2 -6
  126. package/dist/commands/status-watch.js +1 -2
  127. package/dist/commands/status.js +2 -5
  128. package/dist/commands/task-init.js +2 -3
  129. package/dist/commands/tutorial.js +2 -2
  130. package/dist/commands/update.js +1 -1
  131. package/dist/completions-cache.js +1 -1
  132. package/dist/console-classifier.js +19 -0
  133. package/dist/discovery.js +1 -1
  134. package/dist/doctor.js +3 -4
  135. package/dist/funding-execution-context.js +15 -1
  136. package/dist/host.js +32 -0
  137. package/dist/index.js +1 -6
  138. package/dist/live-tsx.js +49 -0
  139. package/dist/mm-harness-cli.js +2 -4
  140. package/dist/network-observation.js +4 -4
  141. package/dist/paths.js +48 -78
  142. package/dist/performance-observation.js +2 -2
  143. package/dist/progress.js +1 -1
  144. package/dist/recipe-assistance-context.js +2 -4
  145. package/dist/recipe-security.js +2 -59
  146. package/dist/review/knowledge.js +3 -3
  147. package/dist/runner.js +5 -3
  148. package/dist/runtime-context.js +1 -1
  149. package/dist/task-view.js +3 -4
  150. package/docs/CONTRIBUTING.md +3 -3
  151. package/docs/cli-contract.md +2 -2
  152. package/docs/feature-guard.md +90 -0
  153. package/library/README.md +3 -1
  154. package/library/actions/core/perps/_controller.mjs +153 -130
  155. package/library/actions/core/perps/quote_fees.mjs +58 -0
  156. package/library/actions/core/wallet/_fixture-accounts.mjs +69 -0
  157. package/library/actions/core/wallet/list_accounts.mjs +14 -57
  158. package/library/actions/extension/feature_flags/state.mjs +1 -1
  159. package/library/actions/extension/platform/cdp.mjs +2 -8
  160. package/library/actions/harness-exports.mjs +1 -6
  161. package/library/actions/mobile/app/network-control.mjs +6 -8
  162. package/library/actions/mobile/perps/prepare_local_snapshot_endpoint.mjs +1 -1
  163. package/library/actions/mobile/platform/bridge.mjs +8 -8
  164. package/library/actions/mobile/platform/native-session-name.mjs +21 -1
  165. package/library/actions/mobile/platform/native-session.mjs +3 -4
  166. package/library/actions/mobile/platform/observe-ui.mjs +12 -6
  167. package/library/actions/mobile/ui/native-navigation.mjs +4 -3
  168. package/library/actions/mobile/wallet/native-ui.mjs +3 -2
  169. package/library/actions/shared/analytics/_adapter.mjs +1 -1
  170. package/library/actions/shared/console-findings.mjs +1 -1
  171. package/library/actions/terminal/platform/runtime.mjs +2 -1
  172. package/library/manifests/core.action-manifest.json +83 -13
  173. package/package.json +8 -8
  174. package/adapters/extension/lib/slot-title.cjs +0 -292
  175. package/adapters/mobile/bridge-runtime/console-forwarder.cjs +0 -472
  176. package/adapters/mobile/bridge-runtime/lib/bridge-errors.cjs +0 -125
  177. package/adapters/mobile/bridge-runtime/lib/cdp-broker.cjs +0 -1055
  178. package/adapters/mobile/bridge-runtime/lib/cdp-eval.cjs +0 -110
  179. package/adapters/mobile/bridge-runtime/lib/config.cjs +0 -61
  180. package/adapters/mobile/bridge-runtime/lib/console-format.cjs +0 -53
  181. package/adapters/mobile/bridge-runtime/lib/devtools-proxy.cjs +0 -177
  182. package/adapters/mobile/bridge-runtime/lib/issue-capture.cjs +0 -446
  183. package/adapters/mobile/bridge-runtime/lib/match-bridge-target.cjs +0 -84
  184. package/adapters/mobile/bridge-runtime/lib/target-discovery.cjs +0 -403
  185. package/adapters/mobile/bridge-runtime/lib/ws-client.cjs +0 -116
  186. package/adapters/mobile/coalesce-metro-log.cjs +0 -24
  187. package/adapters/mobile/launch-metro.cjs +0 -77
  188. package/adapters/mobile/metro-config.cjs +0 -98
  189. package/adapters/mobile/metro-log-generation.cjs +0 -106
  190. package/dist/adapters/mobile/frame-metrics.js +0 -118
  191. package/dist/adapters/mobile/video-recorder.js +0 -289
  192. package/dist/artifact-files.js +0 -92
  193. package/dist/checkout-lock.js +0 -149
  194. package/dist/cli-color.js +0 -98
  195. package/dist/command-journal.js +0 -308
  196. package/dist/commands/last.js +0 -60
  197. package/dist/commands/launch/index.js +0 -109
  198. package/dist/commands/parse-args.js +0 -279
  199. package/dist/commands/reload.js +0 -41
  200. package/dist/commands/run-report.js +0 -241
  201. package/dist/commands/shared.js +0 -323
  202. package/dist/commands/stop.js +0 -60
  203. package/dist/devices.js +0 -100
  204. package/dist/execution-provenance.js +0 -332
  205. package/dist/harness.js +0 -451
  206. package/dist/heal-bounds.js +0 -137
  207. package/dist/json-stream.js +0 -60
  208. package/dist/leaf-invoke.js +0 -19
  209. package/dist/library-provenance.js +0 -33
  210. package/dist/live-adapter-contract.js +0 -380
  211. package/dist/recording-target.js +0 -120
  212. package/dist/run-diagnostics.js +0 -364
  213. package/dist/run-recording.js +0 -481
  214. package/dist/runtime-proof.js +0 -90
  215. package/library/actions/mobile/platform/tool-paths.mjs +0 -123
@@ -1,3 +1,5 @@
1
+ import { isRecord } from "@farmslot/recipe-cli/harness";
2
+ import { verifyOwnedCollectorControl } from "../console-capture.js";
1
3
  import { devicePlatformFromEnv } from "../performance/device-platform.js";
2
4
  import {
3
5
  ensureTerminalConsoleCapture,
@@ -11,10 +13,31 @@ const terminalDiagnostics = {
11
13
  start: (projectRoot) => ensureTerminalConsoleCapture(projectRoot),
12
14
  files: (projectRoot) => terminalCaptureFiles(projectRoot),
13
15
  cdpPort: () => terminalCdpPort(),
14
- verifyControl: (capture) => verifyTerminalConsoleControl(capture)
16
+ verifyControl: (capture) => verifyOwnedCollectorControl(capture, () => verifyTerminalConsoleControl(capture))
15
17
  },
16
- walletLog: (projectRoot) => terminalRuntimeFile(projectRoot, "wallet-requests.jsonl")
18
+ requestLog: {
19
+ path: (projectRoot) => terminalRuntimeFile(projectRoot, "wallet-requests.jsonl"),
20
+ findings: (lines) => walletRequestFindings(lines)
21
+ }
17
22
  };
23
+ function walletRequestFindings(lines) {
24
+ const findings = [];
25
+ for (const line of lines) {
26
+ let entry;
27
+ try {
28
+ entry = JSON.parse(line);
29
+ } catch {
30
+ continue;
31
+ }
32
+ if (!isRecord(entry)) continue;
33
+ let text = null;
34
+ if (entry.kind === "blocked-mainnet" && entry.probe !== true) text = `blocked-mainnet: ${String(entry.transport ?? "request")} to ${String(entry.url ?? "?")}`;
35
+ else if (entry.kind === "refused-mainnet") text = `refused-mainnet: ${String(entry.method ?? "?")} (${String(entry.reason ?? "?")})`;
36
+ else if (entry.kind === "unattributed") text = `unattributed wallet ${entry.binding === "request" ? "request" : "log entry"}${typeof entry.method === "string" ? ` (${entry.method})` : ""}`;
37
+ if (text) findings.push({ level: "error", source: "wallet", text });
38
+ }
39
+ return findings;
40
+ }
18
41
  const terminalObservation = {
19
42
  network: {
20
43
  backend: async (_target, env, artifactsDir) => (await import("../../network-observation.js")).createExtensionNetworkBackend(env, artifactsDir)
@@ -1,5 +1,6 @@
1
+ import { shellQuote } from "@farmslot/recipe-cli/harness";
1
2
  import path from "node:path";
2
- import { shellQuote } from "../../commands/parse-args.js";
3
+ import { defineAdapter } from "@farmslot/adapter-sdk";
3
4
  import fs from "node:fs";
4
5
  import { TERMINAL_CONSOLE_FILES, terminalRuntimeFile } from "./console-capture.js";
5
6
  import { stopTerminalBrowserSync } from "./stop.js";
@@ -8,6 +9,7 @@ import { terminalActions } from "./actions.js";
8
9
  import { terminalHarness, terminalRuntimeContext } from "./overlay.js";
9
10
  import { terminalReadiness } from "./readiness.js";
10
11
  import { terminalDiagnostics, terminalObservation } from "./run.js";
12
+ import { checkoutHas, checkoutHasDir } from "../checkout-files.js";
11
13
  function portFromEnv(...names) {
12
14
  for (const name of names) {
13
15
  const raw = process.env[name];
@@ -29,8 +31,9 @@ function terminalSignerFor(target) {
29
31
  }
30
32
  return process.env.TERMINAL_SIGNER || "extension";
31
33
  }
32
- const terminalSurface = {
33
- adapter: "terminal",
34
+ const terminalSurface = defineAdapter({
35
+ id: "terminal",
36
+ sdkVersion: 1,
34
37
  headless: false,
35
38
  resolveSlotPorts() {
36
39
  },
@@ -96,6 +99,11 @@ const terminalSurface = {
96
99
  appLogSource(target) {
97
100
  return { label: "app-console", path: terminalRuntimeFile(target, TERMINAL_CONSOLE_FILES.app) };
98
101
  },
102
+ detect: {
103
+ remote: (url) => url.includes("va-mmcx-terminal"),
104
+ files: (target) => checkoutHasDir(target, "src/features/perpetuals") && ["next.config.ts", "next.config.mjs", "next.config.js"].some((file) => checkoutHas(target, file))
105
+ },
106
+ flags: { launch: ["freshProfile", "headless", "headful"] },
99
107
  hints: {
100
108
  launch: "mm-harness launch --adapter terminal --cdp-port <port> --watcher-port <app port>",
101
109
  relaunch: "mm-harness launch --adapter terminal --fresh-profile",
@@ -116,7 +124,7 @@ const terminalSurface = {
116
124
  },
117
125
  diagnostics: terminalDiagnostics,
118
126
  observation: terminalObservation
119
- };
127
+ });
120
128
  adapterRegistry.register(terminalSurface);
121
129
  export {
122
130
  terminalAppPort,
package/dist/adapters.js CHANGED
@@ -1,9 +1,10 @@
1
1
  import http from "node:http";
2
2
  import { createHash } from "node:crypto";
3
3
  import { compatibilityMode, fixtureSummary, repoShape } from "./doctor.js";
4
- import {
5
- runLiveAdapterScript
6
- } from "./live-adapter-contract.js";
4
+ import { runLiveAdapterScript } from "@farmslot/recipe-cli/harness";
5
+ import { trustedMutationContextExtras } from "./funding-execution-context.js";
6
+ import { LIBRARY_ACTION_NAMESPACE } from "./paths.js";
7
+ import { liveTsxCandidates } from "./live-tsx.js";
7
8
  import { resolveWalletImportCredentials, validateWalletImportOptions } from "../library/actions/shared/wallet/import-source.mjs";
8
9
  import { isRecord, traceText } from "./action-values.js";
9
10
  import { getAdapterSurface } from "./adapters/surface.js";
@@ -109,9 +110,12 @@ async function runLiveFirst(platform, action, node, context, forceLive = false,
109
110
  const live = await runLiveAdapterScript({
110
111
  platform,
111
112
  action,
113
+ namespace: LIBRARY_ACTION_NAMESPACE,
112
114
  node,
113
115
  context,
114
- prepared: preparedLiveAdapters?.get(action)
116
+ prepared: preparedLiveAdapters?.get(action),
117
+ contextExtras: trustedMutationContextExtras(context),
118
+ tsxCandidates: liveTsxCandidates()
115
119
  });
116
120
  if (!live) return null;
117
121
  const liveResult = isRecord(live.result) ? live.result : { result: live.result };
@@ -1,5 +1,5 @@
1
+ import { optionString, usageError } from "@farmslot/recipe-cli/harness";
1
2
  import { assessmentProvider } from "./assessment-providers.js";
2
- import { optionString, usageError } from "./commands/parse-args.js";
3
3
  import { configPath, parseAdvisorSettings, readConfig } from "./review/knowledge.js";
4
4
  function resolveAdvisorPolicy(options, env = process.env, config) {
5
5
  const saved = (config ?? readConfig(configPath(env))).advisor ?? {};
@@ -1,8 +1,7 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { color } from "./cli-color.js";
3
+ import { color, recipeRuntimeDir } from "@farmslot/recipe-cli/harness";
4
4
  import { renderRuntimeContext, runtimeContextSummary } from "./doctor.js";
5
- import { recipeRuntimeDir } from "./paths.js";
6
5
  import {
7
6
  configPath,
8
7
  declaredLibraryPathEnv,
package/dist/cli.js CHANGED
@@ -1,5 +1,17 @@
1
+ import "./host.js";
2
+ import "./adapters/surface.js";
3
+ import {
4
+ detectAdapter,
5
+ handleHarness,
6
+ handleLast,
7
+ handleLaunch,
8
+ handleReload,
9
+ handleStop,
10
+ parseArgs,
11
+ targetPath
12
+ } from "@farmslot/recipe-cli/harness";
13
+ import { stopProjectCollector } from "../library/actions/shared/analytics/collector.mjs";
1
14
  import { adapterRegistry } from "./adapters/registry.js";
2
- import { detectAdapter, handleHarness } from "./harness.js";
3
15
  import { handleActions } from "./commands/manifest.js";
4
16
  import { handleDoctor } from "./commands/doctor.js";
5
17
  import { handleProvision } from "./commands/provision.js";
@@ -11,12 +23,9 @@ import { handleEnsureReady } from "./commands/ensure-ready.js";
11
23
  import { handleRun } from "./commands/run.js";
12
24
  import { handleSelfTest } from "./commands/self-test.js";
13
25
  import { handleCall } from "./commands/call.js";
14
- import { handleStop } from "./commands/stop.js";
15
26
  import { handleCompletionCandidates, invalidateCompletionCache } from "./commands/completion-candidates.js";
16
- import { handleLaunch } from "./commands/launch/index.js";
17
27
  import { handleLogs } from "./commands/logs.js";
18
28
  import { handleDebug } from "./commands/debug.js";
19
- import { handleReload } from "./commands/reload.js";
20
29
  import { handleFixtures } from "./commands/fixtures.js";
21
30
  import { handleRecipeQuality } from "./commands/recipe-quality.js";
22
31
  import { handleStatus } from "./commands/status.js";
@@ -25,12 +34,17 @@ import { handleChecklist } from "./commands/checklist.js";
25
34
  import { handleExecutionTemplate } from "./commands/execution-template.js";
26
35
  import { handlePrepare } from "./commands/prepare.js";
27
36
  import { handleTaskInit } from "./commands/task-init.js";
28
- import { handleLast } from "./commands/last.js";
29
37
  import { handleReview } from "./commands/review.js";
30
38
  import { handleDomain } from "./commands/domain.js";
31
39
  import { handleConfig } from "./commands/config.js";
32
40
  import { handlePrBody } from "./commands/pr-body.js";
33
- import { parseArgs, targetPath } from "./commands/parse-args.js";
41
+ import { overlayCommandOptions } from "./commands/overlay.js";
42
+ const stopOptions = {
43
+ companions: async (target) => {
44
+ const collector = await stopProjectCollector(target);
45
+ return collector.stopped && collector.pid !== null ? [{ label: "analytics collector", pid: collector.pid }] : [];
46
+ }
47
+ };
34
48
  const COMMANDS = {
35
49
  actions: handleActions,
36
50
  doctor: handleDoctor,
@@ -98,35 +112,34 @@ async function main(argv) {
98
112
  return command ? 0 : 2;
99
113
  }
100
114
  if (command === "status" || command === "health" || command === "home") {
101
- return handleStatus(parseArgs(argv.slice(1), "status"));
115
+ return handleStatus(parseArgs(argv.slice(1)));
102
116
  }
103
117
  if (command === "call") return handleCall(argv.slice(1));
104
118
  if (command === "completion-candidates") return handleCompletionCandidates(argv.slice(1));
105
- if (command === "provision") return handleProvision(parseArgs(argv.slice(1), command));
119
+ if (command === "provision") return handleProvision(parseArgs(argv.slice(1)));
106
120
  if (OVERLAY_COMMANDS.includes(command)) {
107
121
  if (command === "verify" && process.env.MM_HARNESS_SKIP_OVERLAY_ENSURE !== "1") {
108
122
  try {
109
- const { options } = parseArgs(argv.slice(1), command);
123
+ const { options } = parseArgs(argv.slice(1));
110
124
  const target = targetPath(options);
111
125
  const adapterRaw = (typeof options["adapter"] === "string" ? options["adapter"] : void 0) ?? (typeof options["platform"] === "string" ? options["platform"] : void 0) ?? detectAdapter(target);
112
- await import("./adapters/surface.js");
113
126
  if (adapterRaw && adapterRegistry.has(adapterRaw)) {
114
127
  await handleHarness(["install", "--platform", adapterRaw, "--target", target, "--quiet"]);
115
128
  }
116
129
  } catch {
117
130
  }
118
131
  }
119
- const code = await handleHarness(argv);
132
+ const code = await handleHarness(argv, overlayCommandOptions);
120
133
  if (code === 0 && command === "install") {
121
134
  try {
122
- invalidateCompletionCache(targetPath(parseArgs(argv.slice(1), command).options));
135
+ invalidateCompletionCache(targetPath(parseArgs(argv.slice(1)).options));
123
136
  } catch {
124
137
  }
125
138
  }
126
139
  return code;
127
140
  }
128
141
  if (command === "launch") return handleLaunch(argv.slice(1));
129
- if (command === "stop") return handleStop(argv.slice(1));
142
+ if (command === "stop") return handleStop(argv.slice(1), stopOptions);
130
143
  if (command === "logs") return handleLogs(argv.slice(1));
131
144
  if (command === "debug") return handleDebug(argv.slice(1));
132
145
  if (command === "reload") return handleReload(argv.slice(1));
@@ -137,14 +150,14 @@ async function main(argv) {
137
150
  if (command === "execution-template") return handleExecutionTemplate(argv.slice(1));
138
151
  if (command === "task") return handleTaskInit(argv.slice(1));
139
152
  if (command === "prepare") return handlePrepare(argv.slice(1));
140
- if (command === "last") return handleLast(parseArgs(argv.slice(1), command));
153
+ if (command === "last") return handleLast(parseArgs(argv.slice(1)));
141
154
  if (command === "review") return handleReview(argv.slice(1));
142
155
  if (command === "domain") return handleDomain(argv.slice(1));
143
156
  if (command === "config") return handleConfig(argv.slice(1));
144
157
  if (command === "pr-body") return handlePrBody(argv.slice(1));
145
158
  const handler = COMMANDS[command];
146
159
  if (!handler) throw new Error(`Unknown command: ${command}`);
147
- return handler(parseArgs(argv.slice(1), command));
160
+ return handler(parseArgs(argv.slice(1), command === "runtime-decision" ? { recordIsFlag: true } : {}));
148
161
  }
149
162
  if (!globalThis.__MM_HARNESS_WRAPPER__) {
150
163
  try {
@@ -1,3 +1,4 @@
1
+ import { closest } from "@farmslot/recipe-cli/harness";
1
2
  const bool = () => ({ kind: "boolean" });
2
3
  const value = (choices) => ({ kind: "value", ...choices ? { choices } : {} });
3
4
  const optionalValue = (choices) => ({ kind: "optional-value", ...choices ? { choices } : {} });
@@ -698,34 +699,8 @@ function actionFor(received, suggestion, example) {
698
699
  function exampleFor(command, examples) {
699
700
  return command ? examples[command] ?? `mm-harness ${command} --help` : "mm-harness --help";
700
701
  }
701
- function closest(input, candidates) {
702
- if (candidates.length === 0) return void 0;
703
- const ranked = candidates.map((candidate) => ({ candidate, distance: levenshtein(input, candidate) })).sort((left, right) => left.distance - right.distance || left.candidate.localeCompare(right.candidate));
704
- const best = ranked[0];
705
- if (!best) return void 0;
706
- const threshold = Math.max(2, Math.floor(Math.max(input.length, best.candidate.length) / 3));
707
- return best.distance <= threshold ? best.candidate : void 0;
708
- }
709
- function levenshtein(left, right) {
710
- let twoBack;
711
- let prior = Array.from({ length: right.length + 1 }, (_, index) => index);
712
- for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
713
- const current = [leftIndex];
714
- for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {
715
- const substitution = prior[rightIndex - 1] + (left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1);
716
- current[rightIndex] = Math.min((current[rightIndex - 1] ?? 0) + 1, (prior[rightIndex] ?? 0) + 1, substitution);
717
- if (twoBack && leftIndex > 1 && rightIndex > 1 && left[leftIndex - 1] === right[rightIndex - 2] && left[leftIndex - 2] === right[rightIndex - 1]) {
718
- current[rightIndex] = Math.min(current[rightIndex] ?? 0, (twoBack[rightIndex - 2] ?? 0) + 1);
719
- }
720
- }
721
- twoBack = prior;
722
- prior = current;
723
- }
724
- return prior[right.length] ?? right.length;
725
- }
726
702
  export {
727
703
  PUBLIC_COMMAND_CONTRACTS,
728
- closest,
729
704
  publicCommandNames,
730
705
  publicCommandTokens,
731
706
  validatePublicInvocation
@@ -3,9 +3,7 @@ import { randomUUID } from "node:crypto";
3
3
  import path from "node:path";
4
4
  import { resolveActionManifest } from "../manifest.js";
5
5
  import { importRecipeProtocol } from "../paths.js";
6
- import { conciseFailureForHuman, recipeRunning } from "../heal-bounds.js";
7
- import { color } from "../cli-color.js";
8
- import { checkoutBusyOut, EXIT, usageOut } from "./shared.js";
6
+ import { color, acquireCheckoutLock, isSensitiveKey, recordCommandEvidence, redactStructuredValue, conciseFailureForHuman, recipeRunning, checkoutBusyOut, EXIT, usageOut, parseArgs, isRecord, optionFlag, optionString, optionStrings, resolveAdapter, shellQuote, usageError } from "@farmslot/recipe-cli/harness";
9
7
  import {
10
8
  actionLibraryContextArgs,
11
9
  actionExampleCommand,
@@ -13,17 +11,6 @@ import {
13
11
  resolveActionCapabilityMatrix
14
12
  } from "./manifest.js";
15
13
  import { fuzzyResolveActions, resolveActionCapabilityRefusal } from "@farmslot/recipe-cli";
16
- import {
17
- parseArgs,
18
- isRecord,
19
- optionFlag,
20
- optionString,
21
- optionStrings,
22
- resolveAdapter,
23
- runtimeOptionsFromCli,
24
- shellQuote,
25
- usageError
26
- } from "./parse-args.js";
27
14
  import { getAdapterSurface } from "../adapters/surface.js";
28
15
  import { handleListExecutables } from "./list-executables.js";
29
16
  import { applyDeviceTargeting } from "./device-target.js";
@@ -38,21 +25,17 @@ import {
38
25
  synthesizeOneNodeRecipe,
39
26
  validateRecipeAdapterAware
40
27
  } from "./run-engine.js";
41
- import { acquireCheckoutLock } from "../checkout-lock.js";
42
- import { formatRunDiagnosticsForHuman, readRunDiagnosticsDocument } from "../run-diagnostics.js";
43
28
  import {
44
29
  startRunNetworkObservation
45
30
  } from "../network-observation.js";
46
31
  import {
47
32
  startRunPerformanceObservation
48
33
  } from "../performance-observation.js";
49
- import { recipeTrustFailure } from "../recipe-security.js";
50
- import { isSensitiveKey, recordCommandEvidence, redactStructuredValue } from "../command-journal.js";
51
- import { closest } from "../command-contract.js";
52
- import { ProvenanceDriftError } from "../execution-provenance.js";
34
+ import { closest, formatRunDiagnosticsForHuman, ProvenanceDriftError, readRunDiagnosticsDocument, recipeRunOptionsFromCli, recipeTrustFailure } from "@farmslot/recipe-cli/harness";
35
+ import { fundingOptionsFromCli } from "../funding-execution-context.js";
53
36
  async function handleCall(argv) {
54
37
  if (argv.includes("--list")) {
55
- const { options: options2 } = parseArgs(argv, "call");
38
+ const { options: options2 } = parseArgs(argv);
56
39
  return handleListExecutables("call", options2);
57
40
  }
58
41
  if (argv.length > 0 && argv[0].startsWith("--")) {
@@ -61,7 +44,7 @@ async function handleCall(argv) {
61
44
  return EXIT.usage;
62
45
  }
63
46
  const { action: shortName, args, rest } = parseCallArgs(argv);
64
- const { options } = parseArgs(rest, "call");
47
+ const { options } = parseArgs(rest);
65
48
  if (["domain", "source", "sort"].some((name) => optionString(options, name) !== void 0)) {
66
49
  throw usageError("--domain, --source, and --sort require call --list.");
67
50
  }
@@ -214,7 +197,10 @@ async function handleCall(argv) {
214
197
  }
215
198
  const artifactsDir = optionString(options, "artifactsDir") ?? defaultCallArtifactsDir(target, resolvedAction);
216
199
  recordCommandEvidence(artifactsDir);
217
- const requestedRuntimeOptions = runtimeOptionsFromCli(options);
200
+ const requestedRuntimeOptions = {
201
+ ...recipeRunOptionsFromCli(adapter, options),
202
+ ...fundingOptionsFromCli(options)
203
+ };
218
204
  const inheritedSource = process.env.FARMSLOT_RECIPE_SOURCE_TRUST || process.env.FARMSLOT_RECIPE_SOURCE_KIND || process.env.FARMSLOT_RECIPE_SOURCE_NAME || process.env.FARMSLOT_RECIPE_SOURCE_DIGEST;
219
205
  let networkObservation;
220
206
  let performanceObservation;
@@ -509,7 +495,7 @@ function redactCallValue(value, key = "") {
509
495
  }
510
496
  async function handleCallHelp(argv, genericHelp) {
511
497
  const { action: shortName, rest } = parseCallArgs(argv.filter((arg) => arg !== "--help" && arg !== "-h"));
512
- const { options } = parseArgs(rest, "call");
498
+ const { options } = parseArgs(rest);
513
499
  let adapter;
514
500
  let manifest;
515
501
  let actionSources = /* @__PURE__ */ new Map();
@@ -1,16 +1,15 @@
1
+ import { detectAdapter, EXIT, usageOut, optionFlag, optionString, parseArgs, shellQuote } from "@farmslot/recipe-cli/harness";
1
2
  import { spawnSync } from "node:child_process";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
- import { detectAdapter } from "../harness.js";
5
- import { EXIT, usageOut } from "./shared.js";
6
- import { optionFlag, optionString, parseArgs, shellQuote } from "./parse-args.js";
5
+ import "../adapters/surface.js";
7
6
  const USAGE = "mm-harness check diff [--fix] [--target <repo>] [--adapter mobile|extension|core] [--base <ref>] [--profile fast|full] [--artifacts-dir <dir>] [--json]";
8
7
  const JS_TS_EXT_RE = /\.(?:c|m)?jsx?$|\.tsx?$/u;
9
8
  const FORMAT_EXT_RE = /\.(?:c|m)?jsx?$|\.tsx?$|\.json$|\.md$|\.css$|\.scss$|\.ya?ml$/u;
10
9
  const TEST_FILE_RE = /(?:^|[./_-])(?:test|spec)\.(?:c|m)?jsx?$|(?:^|[./_-])(?:test|spec)\.tsx?$/u;
11
10
  const ESLINT_SUPPRESSION_RE = /^\s*eslint-disable(?:-line|-next-line)?\b/u;
12
11
  async function handleCheck(argv) {
13
- const { positional, options } = parseArgs(argv, "check");
12
+ const { positional, options } = parseArgs(argv);
14
13
  const action = positional[0];
15
14
  const json = optionFlag(options, "json");
16
15
  const fix = optionFlag(options, "fix");
@@ -1,10 +1,10 @@
1
+ import { EXIT } from "@farmslot/recipe-cli/harness";
1
2
  import { spawnSync } from "node:child_process";
2
3
  import fs from "node:fs";
3
4
  import { createRequire } from "node:module";
4
5
  import path from "node:path";
5
6
  import { HANDOFF_INPUT } from "@farmslot/agent-runtime";
6
7
  import { enumerateChecklistCheckboxes, isTerminalWorkerSignalStatus } from "@farmslot/protocol";
7
- import { EXIT } from "./shared.js";
8
8
  const require2 = createRequire(import.meta.url);
9
9
  const MARK_SCRIPT = require2.resolve(
10
10
  "@farmslot/agent-runtime/scripts/mark-checklist-step.cjs"
@@ -1,3 +1,4 @@
1
+ import { EXIT, parseArgs, optionFlag, optionString, optionStrings, resolveAdapter, targetPath } from "@farmslot/recipe-cli/harness";
1
2
  import { resolveActionManifest } from "../manifest.js";
2
3
  import {
3
4
  invalidateCompletionCache,
@@ -5,19 +6,10 @@ import {
5
6
  writeCompletionCandidates
6
7
  } from "../completions-cache.js";
7
8
  import { importRecipeProtocol } from "../paths.js";
8
- import { EXIT } from "./shared.js";
9
- import {
10
- parseArgs,
11
- optionFlag,
12
- optionString,
13
- optionStrings,
14
- resolveAdapter,
15
- targetPath
16
- } from "./parse-args.js";
17
9
  import { listRunnableRecipes, resolveMetaMaskLibrarySources } from "./run-engine.js";
18
10
  async function handleCompletionCandidates(argv) {
19
11
  const kind = argv[0];
20
- const { options } = parseArgs(argv.slice(1), "completion-candidates");
12
+ const { options } = parseArgs(argv.slice(1));
21
13
  const json = optionFlag(options, "json");
22
14
  if (kind !== "actions" && kind !== "recipes") {
23
15
  console.error("completion-candidates requires <actions|recipes>.");
@@ -1,3 +1,4 @@
1
+ import { optionFlag, parseArgs, usageError } from "@farmslot/recipe-cli/harness";
1
2
  import path from "node:path";
2
3
  import {
3
4
  configPath,
@@ -6,7 +7,6 @@ import {
6
7
  REVIEW_ADAPTERS,
7
8
  writeConfig
8
9
  } from "../review/knowledge.js";
9
- import { optionFlag, parseArgs, usageError } from "./parse-args.js";
10
10
  const USAGE = "Usage: mm-harness config <list|path|get <key>|set <key> <value>|unset <key>> [--json]\n keys: libraries.<name>, references.<mobile|extension|core|terminal>, advisor.<enabled|provider|model|stages>";
11
11
  function parseKey(raw) {
12
12
  if (!raw) throw usageError(USAGE);
@@ -36,7 +36,7 @@ function setValue(config, key, value) {
36
36
  else config[key.section] = section;
37
37
  }
38
38
  async function handleConfig(argv) {
39
- const parsed = parseArgs(argv, "config");
39
+ const parsed = parseArgs(argv);
40
40
  const json = optionFlag(parsed.options, "json");
41
41
  const [action, rawKey, rawValue] = parsed.positional;
42
42
  const expectedPositionals = { path: 1, list: 1, get: 2, set: 3, unset: 2 }[action ?? "list"];
@@ -1,12 +1,24 @@
1
1
  import { createRequire } from "node:module";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
+ import { resolveLiveTsx } from "../live-tsx.js";
4
5
  const requireFromHarness = createRequire(import.meta.url);
5
6
  const CORE_RUNTIME_DEPS = ["immer"];
6
7
  function coreDependencyBlock(target) {
7
8
  const resolved = path.resolve(target);
8
9
  const nodeLinker = readYarnNodeLinker(resolved);
9
10
  const installAction = `cd ${shellQuote(resolved)} && yarn install --immutable`;
11
+ if (!resolveLiveTsx(resolved)) {
12
+ return process.env.TSX_BIN ? {
13
+ code: "CORE_TS_RUNNER_MISSING",
14
+ message: `TSX_BIN is ${process.env.TSX_BIN}, which is not an executable on PATH or relative to the checkout.`,
15
+ userAction: "unset TSX_BIN to use the tsx mm-harness ships, or point it at an existing tsx"
16
+ } : {
17
+ code: "CORE_TS_RUNNER_MISSING",
18
+ message: "no tsx runtime found for core actions (mm-harness ships one; this install is missing it).",
19
+ userAction: "reinstall mm-harness (npm install -g @deeeed/metamask-harness), or set TSX_BIN"
20
+ };
21
+ }
10
22
  if (nodeLinker === "pnp") {
11
23
  if (!fs.existsSync(path.join(resolved, ".pnp.cjs"))) {
12
24
  return {
@@ -24,13 +36,6 @@ function coreDependencyBlock(target) {
24
36
  userAction: installAction
25
37
  };
26
38
  }
27
- if (!fs.existsSync(path.join(resolved, "node_modules/.bin/tsx"))) {
28
- return {
29
- code: "CORE_DEPS_INCOMPLETE",
30
- message: "core dependencies are incomplete (node_modules/.bin/tsx is missing).",
31
- userAction: installAction
32
- };
33
- }
34
39
  for (const dependency of CORE_RUNTIME_DEPS) {
35
40
  if (!canResolveFromTarget(dependency, resolved)) {
36
41
  return {
@@ -1,14 +1,14 @@
1
+ import { adapterDetectNext, EXIT, flag, parseFlags, resolveFlagsAdapter, spawnScript, targetOf, usageOut } from "@farmslot/recipe-cli/harness";
1
2
  import path from "node:path";
2
3
  import { runnerDir } from "../paths.js";
3
4
  import { getAdapterSurface } from "../adapters/surface.js";
4
- import { ADAPTER_DETECT_NEXT, EXIT, flag, parseFlags, resolveAdapter, spawnScript, targetOf, usageOut } from "./shared.js";
5
5
  const DEBUG_BOOLEANS = /* @__PURE__ */ new Set(["worker", "devMenu", "json", "noOpen"]);
6
6
  async function handleDebug(argv) {
7
7
  const { options } = parseFlags(argv, DEBUG_BOOLEANS);
8
8
  const json = flag(options, "json");
9
9
  const target = targetOf(options);
10
- const adapter = resolveAdapter(options, target);
11
- if (!adapter) return usageOut(json, "debug", `could not detect the MetaMask repo type for ${target}`, ADAPTER_DETECT_NEXT);
10
+ const adapter = resolveFlagsAdapter(options, target);
11
+ if (!adapter) return usageOut(json, "debug", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
12
12
  const surface = getAdapterSurface(adapter);
13
13
  if (surface.headless) return usageOut(json, "debug", `${adapter} is headless; there is no debug console.`, surface.hints.relaunch);
14
14
  surface.resolveSlotPorts(target);
@@ -1,12 +1,12 @@
1
+ import { optionString, shellQuoteArg, targetPath } from "@farmslot/recipe-cli/harness";
1
2
  import { execFileSync } from "node:child_process";
2
- import { resolveMobileToolPath } from "../../library/actions/mobile/platform/tool-paths.mjs";
3
+ import { resolveMobileToolPath } from "@farmslot/adapter-rn";
3
4
  import {
4
5
  findAvailableIosSimulatorById,
5
6
  listConnectedDevices
6
- } from "../devices.js";
7
+ } from "@farmslot/adapter-rn";
7
8
  import { getAdapterSurface } from "../adapters/surface.js";
8
9
  import { persistExplicitDevicePin } from "../runtime-context.js";
9
- import { optionString, shellQuoteArg, targetPath } from "./parse-args.js";
10
10
  const DEVICE_SELECT_HINT = "Pass --device <name|udid|serial> to select one target. Do not shut down other connected devices to force selection.";
11
11
  function normalizeDeviceName(value) {
12
12
  return value.replace(/_/gu, " ").trim();
@@ -27,7 +27,7 @@ function resolveAndroidModel(serial) {
27
27
  }
28
28
  function setAndroidDeviceEnv(id, fallbackName) {
29
29
  process.env.PLATFORM = "android";
30
- process.env.MM_HARNESS_EXPLICIT_PLATFORM = "android";
30
+ process.env.RECIPE_RN_EXPLICIT_PLATFORM = "android";
31
31
  process.env.ADB_SERIAL = id;
32
32
  process.env.ANDROID_SERIAL = id;
33
33
  process.env.ANDROID_DEVICE = id;
@@ -39,7 +39,7 @@ function setAndroidDeviceEnv(id, fallbackName) {
39
39
  }
40
40
  function setIosDeviceEnv(id, fallbackName) {
41
41
  process.env.PLATFORM = "ios";
42
- process.env.MM_HARNESS_EXPLICIT_PLATFORM = "ios";
42
+ process.env.RECIPE_RN_EXPLICIT_PLATFORM = "ios";
43
43
  process.env.IOS_SIMULATOR = fallbackName?.trim() || id;
44
44
  process.env.SIM_UDID = id;
45
45
  process.env.ADB_SERIAL = "";
@@ -2,28 +2,16 @@ import { execFileSync } from "node:child_process";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { featureFlagReport } from "../feature-flags.js";
5
- import { color } from "../cli-color.js";
5
+ import { color, acquireCheckoutLock, detectAdapter, resolveRuntimeContextPath, ensureOverlay, newHealState, recipeRunning, adapterDetectNext, checkoutBusyOut, EXIT, usageOut, actionManifestPathOption, applyRuntimeDirOption, optionFlag, optionString, shellQuote, targetPath } from "@farmslot/recipe-cli/harness";
6
6
  import { collectCheckoutView, renderCheckoutView } from "../checkout-view.js";
7
7
  import { createDoctorReport, fixtureSummary, requiredDoctorCheckSummary } from "../doctor.js";
8
- import { detectAdapter, resolveRuntimeContextPath } from "../harness.js";
9
8
  import { assertAdapter, runnerDir } from "../paths.js";
10
9
  import { getAdapterSurface } from "../adapters/surface.js";
11
10
  import { loadActionManifest, validateManifest } from "../manifest.js";
12
- import { ensureOverlay, newHealState, recipeRunning } from "../heal-bounds.js";
13
11
  import { applyDeviceTargeting } from "./device-target.js";
14
12
  import { farmslotReadyIndicator } from "./farmslot-ready.js";
15
13
  import { updateStatus } from "./update.js";
16
14
  import { ensureRuntimeContext } from "../runtime-context.js";
17
- import { acquireCheckoutLock } from "../checkout-lock.js";
18
- import { ADAPTER_DETECT_NEXT, checkoutBusyOut, EXIT, usageOut } from "./shared.js";
19
- import {
20
- actionManifestPathOption,
21
- applyRuntimeDirOption,
22
- optionFlag,
23
- optionString,
24
- shellQuote,
25
- targetPath
26
- } from "./parse-args.js";
27
15
  function applyDoctorRuntimePorts(options) {
28
16
  const cdpPort = optionString(options, "cdpPort");
29
17
  if (cdpPort) {
@@ -48,7 +36,7 @@ async function handleDoctor({ options }) {
48
36
  const explicitAdapter = optionString(options, "adapter") ?? (platformOption === "ios" || platformOption === "android" ? "mobile" : platformOption);
49
37
  const adapter = explicitAdapter ?? detectAdapter(target);
50
38
  if (!adapter) {
51
- return usageOut(json, "doctor", `could not detect the MetaMask repo type for ${target}`, ADAPTER_DETECT_NEXT);
39
+ return usageOut(json, "doctor", `could not detect the MetaMask repo type for ${target}`, adapterDetectNext());
52
40
  }
53
41
  assertAdapter(adapter);
54
42
  const { readiness } = getAdapterSurface(adapter);
@@ -1,3 +1,4 @@
1
+ import { optionFlag, optionString, parseArgs, targetPath, usageError } from "@farmslot/recipe-cli/harness";
1
2
  import {
2
3
  changedFiles,
3
4
  classifyDomain,
@@ -5,10 +6,9 @@ import {
5
6
  discoverLibraries,
6
7
  readConfig
7
8
  } from "../review/knowledge.js";
8
- import { optionFlag, optionString, parseArgs, targetPath, usageError } from "./parse-args.js";
9
9
  import { adapterFromOptions } from "./review.js";
10
10
  async function handleDomain(argv) {
11
- const parsed = parseArgs(argv, "domain");
11
+ const parsed = parseArgs(argv);
12
12
  const target = targetPath(parsed.options);
13
13
  const json = optionFlag(parsed.options, "json");
14
14
  const declared = optionString(parsed.options, "domain") ?? process.env.MM_HARNESS_DOMAIN;
@@ -1,11 +1,5 @@
1
+ import { adapterOption, optionFlag, optionString, parsePort, targetPath } from "@farmslot/recipe-cli/harness";
1
2
  import { ensureExtensionReady } from "../adapters/extension/ensure-ready.js";
2
- import {
3
- adapterOption,
4
- optionFlag,
5
- optionString,
6
- parsePort,
7
- targetPath
8
- } from "./parse-args.js";
9
3
  async function handleEnsureReady({ options }) {
10
4
  const adapter = adapterOption(options);
11
5
  if (adapter !== "extension") throw new Error("ensure-ready currently applies to the extension adapter.");