{
  "schemaVersion": 1,
  "description": "Adapter feature surface: one entry per feature script. scripts/adapter-surface-doctor.mjs verifies every entry point exists, answers --help with exit 0, and that no adapter script is missing from this manifest.",
  "features": [
    {
      "id": "mobile/yarn-setup",
      "entry": "adapters/mobile/yarn-setup.sh",
      "kind": "bash",
      "purpose": "Install node_modules for a MetaMask Mobile checkout (yarn setup + pod install on iOS).",
      "inputs": "--target <metamask-mobile dir>; env MOBILE_SKIP_POD_INSTALL",
      "outputs": "node_modules + ios/Pods; exit 0/1/2"
    },
    {
      "id": "mobile/start-metro",
      "entry": "adapters/mobile/start-metro.sh",
      "kind": "bash",
      "purpose": "Ensure the Metro bundler is running for a MetaMask Mobile checkout (start, restart, or skip if valid).",
      "inputs": "--target --port --clear; env WATCHER_PORT, METRO_PORT, MOBILE_METRO_REQUIRED_ENV, METRO_MAX_WORKERS",
      "outputs": "Metro PID file + log; exit 0 ready / 1 timeout / 2 bad args"
    },
    {
      "id": "mobile/start-console-forwarder",
      "entry": "adapters/mobile/start-console-forwarder.sh",
      "kind": "bash",
      "purpose": "Ensure one runner-owned Mobile application console collector is alive after bridge readiness.",
      "inputs": "--target --port --quiet; env WATCHER_PORT, METRO_PORT, METAMASK_RECIPE_CONSOLE_FORWARD",
      "outputs": "app-console.log + collector PID file; exit 0 ready / 1 startup failed / 2 bad args"
    },
    {
      "id": "mobile/launch-console-forwarder",
      "entry": "adapters/mobile/launch-console-forwarder.cjs",
      "kind": "node",
      "purpose": "Detach the Mobile application console collector from command-runner process-group cleanup.",
      "inputs": "--port --out --err",
      "outputs": "collector PID on stdout; exit 0 launched / 1 spawn failed / 2 bad args"
    },
    {
      "id": "mobile/launch-metro",
      "entry": "adapters/mobile/launch-metro.cjs",
      "kind": "node",
      "purpose": "Launch Metro detached from the invoking process group so the runtime survives command cleanup.",
      "inputs": "--target --port --log --pid-file --build-env --runner [--workers] [--clear]",
      "outputs": "Metro PID/launch metadata and redirected log; exit 0/1/2"
    },
    {
      "id": "mobile/metro-log-generation",
      "entry": "adapters/mobile/metro-log-generation.cjs",
      "kind": "module",
      "purpose": "Rotate one Metro generation, retain bounded archives, and publish launch evidence.",
      "inputs": "runtime directory, Metro port, rotation reason; env MM_HARNESS_METRO_LOG_ARCHIVE_COUNT, MM_HARNESS_METRO_LOG_ARCHIVE_BYTES",
      "outputs": "metro.log, archived logs, metro-generation.json"
    },
    {
      "id": "mobile/coalesce-metro-log",
      "entry": "adapters/mobile/coalesce-metro-log.cjs",
      "kind": "module",
      "purpose": "Coalesce repetitive Metro percentage progress while preserving diagnostics.",
      "inputs": "Metro output on stdin",
      "outputs": "errors, completion, and timestamped meaningful progress on stdout"
    },
    {
      "id": "mobile/metro-config",
      "entry": "adapters/mobile/metro-config.cjs",
      "kind": "module",
      "purpose": "Preserve the product Metro config while excluding the checkout-local temp tree owned by harness evidence and runtime state.",
      "inputs": "base Metro config; env MM_HARNESS_METRO_PROJECT_ROOT, MM_HARNESS_METRO_BASE_CONFIG",
      "outputs": "merged Metro config with resolver.blockList for <projectRoot>/temp"
    },
    {
      "id": "mobile/stop-metro",
      "entry": "adapters/mobile/stop-metro.sh",
      "kind": "bash",
      "purpose": "Stop the port-scoped Metro bundler this checkout owns and close its log-tail window (idempotent).",
      "inputs": "--target --port; env WATCHER_PORT",
      "outputs": "progress on stderr; exit 0 stopped-or-nothing / 1 stop failed / 2 bad args"
    },
    {
      "id": "mobile/reload-app",
      "entry": "adapters/mobile/reload-app.mjs",
      "kind": "node",
      "purpose": "Request an in-place React Native app reload through Metro's protocol-v2 message endpoint.",
      "inputs": "--port --json; env WATCHER_PORT, METRO_PORT",
      "outputs": "reload result on stdout; exit 0 requested / 1 unavailable or invalid input"
    },
    {
      "id": "mobile/prewarm-bundle",
      "entry": "adapters/mobile/prewarm-bundle.sh",
      "kind": "bash",
      "purpose": "Curl the Metro bundle URL before the dev client opens to pre-compile and cache the bundle.",
      "inputs": "--platform ios|android --target --port; env MOBILE_BUNDLE_PREWARM, MOBILE_BUNDLE_PREWARM_TIMEOUT",
      "outputs": "progress on stderr; exit 0 bundle ready / 1 timeout / 2 bad args"
    },
    {
      "id": "mobile/reset-app-data",
      "entry": "adapters/mobile/reset-app-data.sh",
      "kind": "bash",
      "purpose": "Reset exactly one installed MetaMask Mobile app while preserving its install for fixture reapplication.",
      "inputs": "--platform ios|android --target --simulator --adb-serial; env IOS_BUNDLE_ID, ANDROID_PACKAGE_ID",
      "outputs": "selected app data cleared and app restored on iOS / cleared on Android; exit 0/1/2"
    },
    {
      "id": "mobile/open-device",
      "entry": "adapters/mobile/open-device.sh",
      "kind": "bash",
      "purpose": "Open the MetaMask Mobile dev client on a simulator or device via expo-development-client deep link.",
      "inputs": "--platform ios|android --target --simulator --adb-serial --preflight-mode --port; env IOS_SIMULATOR, SIM_UDID, ADB_SERIAL, MOBILE_PREFLIGHT_MODE, WATCHER_PORT",
      "outputs": "progress on stderr; exit 0 opened / 1 open failed / 2 bad args"
    },
    {
      "id": "mobile/wait-for-bridge",
      "entry": "adapters/mobile/wait-for-bridge.sh",
      "kind": "bash",
      "purpose": "Poll the CDP bridge (cdp-bridge.cjs status) until a route target registers; progressive diagnostics on failure.",
      "inputs": "--target --port --max-polls; env WATCHER_PORT, MOBILE_BRIDGE_READY_POLLS",
      "outputs": "progress on stderr; exit 0 bridge ready / 1 timeout"
    },
    {
      "id": "mobile/inject",
      "entry": "adapters/mobile/inject.sh",
      "kind": "bash",
      "purpose": "Install Mobile runner metadata, delegates, and snapshots without modifying product source.",
      "inputs": "--target --no-git-exclude; env RECIPE_HARNESS_ROOT, METAMASK_RUNNER_PROTOCOL_ROOT",
      "outputs": "<harness>/manifest.json + runner/ + scripts/; exit 0/1/2"
    },
    {
      "id": "mobile/cleanup",
      "entry": "adapters/mobile/cleanup.sh",
      "kind": "bash",
      "purpose": "Remove Mobile harness metadata and recorded git excludes without touching product source.",
      "inputs": "--target; env RECIPE_HARNESS_ROOT",
      "outputs": "removes <harness>/; exit 0/1/2"
    },
    {
      "id": "mobile/verify",
      "entry": "adapters/mobile/verify.sh",
      "kind": "bash",
      "purpose": "Verify the mobile harness/runtime is present and healthy (no app launch).",
      "inputs": "--target --artifacts-dir --static-only --platform ios|android --preflight-mode --no-auto-start",
      "outputs": "verify report + evidence; exit 0/1/2"
    },
    {
      "id": "extension/launch",
      "entry": "adapters/extension/launch.sh",
      "kind": "bash",
      "purpose": "Run the caller-supplied prepare command for one slot, then confirm app-control readiness.",
      "inputs": "--target --cdp-port --prepare-cmd --artifacts-dir; env RECIPE_HARNESS_EXTENSION_LAUNCH_CMD",
      "outputs": "<artifacts>/summary.json, logs/{launch.log,extension-readiness.json}; exit 0/1/2"
    },
    {
      "id": "extension/live",
      "entry": "adapters/extension/live.sh",
      "kind": "bash",
      "purpose": "Sequencer: builds the prepare command from the named feature scripts, then launch + verify.",
      "inputs": "--target --cdp-port --launch-existing-dist|--start-watch|--build-lavamoat|--prepare-cmd --dist-dir --chrome-user-data-dir --out --artifacts-dir; env RECIPE_HARNESS_CHROME_BIN, RECIPE_WALLET_FIXTURE, RECIPE_HARNESS_LIVE_KEEP",
      "outputs": "<artifacts>/summary.json + launch/ + verify/ + logs/fixture-source.json; exit 0/1/2"
    },
    {
      "id": "extension/verify",
      "entry": "adapters/extension/verify.sh",
      "kind": "bash",
      "purpose": "Verify the extension harness/runtime is present and healthy (no app launch).",
      "inputs": "--target --out --cdp-port --static-only",
      "outputs": "verify report + evidence; exit 0/1/2"
    },
    {
      "id": "extension/start-watch",
      "entry": "adapters/extension/start-watch.sh",
      "kind": "bash",
      "purpose": "Harness-owned webpack watcher: cache clear, dual-writer refusal, compile-marker wait, baseline record.",
      "inputs": "--target --runtime-dir --runner-bin --summary",
      "outputs": "<runtime-dir>/recipe-harness-webpack.{pid,log}; optional summary; exit 0/1/2"
    },
    {
      "id": "extension/build-lavamoat",
      "entry": "adapters/extension/build-lavamoat.sh",
      "kind": "bash",
      "purpose": "Build a production-like Extension runtime with LavaMoat without enabling test-build fixture semantics.",
      "inputs": "--target --runtime-dir",
      "outputs": "dist/chrome; exit 0/1/2"
    },
    {
      "id": "extension/launch-webpack",
      "entry": "adapters/extension/launch-webpack.cjs",
      "kind": "node",
      "purpose": "Detach the normal yarn start watcher from the launching CLI process while preserving its target, environment, and log.",
      "inputs": "--target --log --pid-file --sync-script --sync-pid-file --sync-log --dist --runtime-dist; optional --port --path-prefix",
      "outputs": "watcher and runtime-sync pids; webpack and sync logs; exit 0/1"
    },
    {
      "id": "extension/sync-webpack-dist",
      "entry": "adapters/extension/sync-webpack-dist.cjs",
      "kind": "node",
      "purpose": "After each successful webpack compile, update the loaded isolated runtime in place so an ordinary browser refresh sees the edit.",
      "inputs": "--watcher-pid --watch-log --target --dist --runtime-dist --pid-file",
      "outputs": "runtime-dist updated in place after successful compile markers; exits with its watcher"
    },
    {
      "id": "extension/configure-runtime-manifest",
      "entry": "adapters/extension/configure-runtime-manifest.cjs",
      "kind": "node",
      "purpose": "Inject the checkout's configured Infura project id into an isolated runtime manifest so Extension test builds cannot trigger browser-native authentication prompts.",
      "inputs": "--target --manifest",
      "outputs": "runtime manifest _flags.testing.infuraProjectId; exit 0/1"
    },
    {
      "id": "extension/check-infura-readiness",
      "entry": "adapters/extension/check-infura-readiness.cjs",
      "kind": "node",
      "purpose": "Reject compiled Infura credentials that are stale or unreachable on Ethereum or Linea before Chromium starts.",
      "inputs": "--target --runtime-dist",
      "outputs": "readiness result without credential values; exit 0/1/2"
    },
    {
      "id": "extension/stamp-runtime-title",
      "entry": "adapters/extension/stamp-runtime-title.cjs",
      "kind": "node",
      "purpose": "Stamp the slot id into isolated Extension page titles so window identity survives browser refreshes.",
      "inputs": "--target --runtime-dist; optional --runtime-dir",
      "outputs": "home.html and sidepanel.html titles updated in the isolated runtime only; exit 0/1"
    },
    {
      "id": "extension/artifact-runtime-state",
      "entry": "adapters/extension/artifact-runtime-state.cjs",
      "kind": "node",
      "purpose": "Record or clear the acquired release artifact identity bound to the loaded runtime snapshot.",
      "inputs": "set|clear --target --runtime-dir; set also requires --source-dir --runtime-dist --provenance",
      "outputs": "<runtime-dir>/extension-release-artifact.json or removal; exit 0/1/2"
    },
    {
      "id": "extension/stop-viewers",
      "entry": "adapters/extension/stop-viewers.sh",
      "kind": "bash",
      "purpose": "Close extension webpack/console tmux viewers and the checkout-scoped console tail.",
      "inputs": "--target <metamask-extension>",
      "outputs": "removes viewer markers and closes matching run-owned windows; exit 0/1/2"
    },
    {
      "id": "extension/console-tail",
      "entry": "adapters/extension/console-tail.mjs",
      "kind": "node",
      "purpose": "Live CDP stream of the running extension console (MV3 service worker + UI pages), re-attaching across service-worker churn; hosts the console tmux tab.",
      "inputs": "--cdp-port [--log <file>]",
      "outputs": "console lines on stdout, optional mirror to --log; exit 0/1/2"
    },
    {
      "id": "extension/snapshot-dist",
      "entry": "adapters/extension/snapshot-dist.sh",
      "kind": "bash",
      "purpose": "Runtime-dist snapshot (rsync, excludes _metadata) with from-git-id freshness guard.",
      "inputs": "--dist --target --runtime-root --runtime-dist --wait-iterations --summary",
      "outputs": "<runtime-dist>/ snapshot; optional summary; exit 0/1/2"
    },
    {
      "id": "extension/seed-fixture",
      "entry": "adapters/extension/seed-fixture.sh",
      "kind": "bash",
      "purpose": "Wallet fixture resolution chain + generate/prefill (pre-launch) and seed-cdp (post-launch) phases.",
      "inputs": "resolve|prefill|seed-cdp; --target --cdp-port --fixture --state --profile --extension-dir --extension-id-file --out --source-out --fixture-script --summary; env RECIPE_WALLET_FIXTURE",
      "outputs": "fixture path on stdout (resolve), provenance/state/parity JSON files; exit 0/1/2"
    },
    {
      "id": "extension/launch-browser",
      "entry": "adapters/extension/launch-browser.cjs",
      "kind": "node",
      "purpose": "Low-level spawn primitive: detached Chrome with isolated profile, CDP on 127.0.0.1, unpacked dist.",
      "inputs": "--cdp-port --chrome-bin --profile --extension-dir --chrome-log --chrome-pid",
      "outputs": "pid file + append-log; exit 0 / non-zero"
    },
    {
      "id": "extension/validation-process-ownership",
      "entry": "adapters/extension/lib/validation-process-ownership.cjs",
      "kind": "lib",
      "purpose": "Resolve browser processes owned by one isolated Extension validation profile.",
      "inputs": "profile path",
      "outputs": "owned process identifiers"
    },
    {
      "id": "extension/refresh-build",
      "entry": "adapters/extension/refresh-build.sh",
      "kind": "bash",
      "purpose": "One-shot rebuild for a frozen slot: yarn start, wait for entry points, kill watcher (fresh AND frozen).",
      "inputs": "--repo --watcher-port --timeout --clean-timeout",
      "outputs": "refreshed dist/chrome; exit 0/1/2"
    },
    {
      "id": "extension/ensure-browser",
      "entry": "adapters/extension/ensure-browser.sh",
      "kind": "bash",
      "purpose": "Ensure the slot's Chromium is running against the existing dist/profile/port (kills + relaunches).",
      "inputs": "--slot-id --repo --cdp-port --runtime-dir --watcher-port; env CHROME_USER_DATA_DIR, RECIPE_HARNESS_ROOT",
      "outputs": "<runtime-dir>/{browser.pid,chromium.pid,extension.id}; exit 0/1"
    },
    {
      "id": "extension/inject",
      "entry": "adapters/extension/inject.mjs",
      "kind": "node",
      "purpose": "Install the extension harness overlay (delegate, manifests, recipes, helper scripts).",
      "inputs": "--target --no-git-exclude; env RECIPE_HARNESS_ROOT, METAMASK_RUNNER_DIR, METAMASK_RUNNER_PROTOCOL_ROOT>FARMSLOT_ROOT",
      "outputs": "<harness>/{manifest.json,action-manifest.json,runner/,scripts/}; exit 0/2/non-zero"
    },
    {
      "id": "extension/cleanup",
      "entry": "adapters/extension/cleanup.mjs",
      "kind": "node",
      "purpose": "Remove the extension overlay and exactly the recorded git-exclude entries.",
      "inputs": "--target; env RECIPE_HARNESS_ROOT",
      "outputs": "removes <harness>/extension; exit 0/2"
    },
    {
      "id": "extension/sidepanel-toggle",
      "entry": "adapters/extension/sidepanel-toggle.sh",
      "kind": "bash",
      "purpose": "Window-mode control for the extension instance: chrome.sidePanel status/open/close/toggle/cycle over the instance's CDP port.",
      "inputs": "<status|open|close|toggle|cycle> --cdp-port --ext-id --agent-dir --settle-ms; env REPO, CDP_PORT, EXT_ID, SETTLE_MS, AGENT_DIR",
      "outputs": "status/progress on stdout; exit 0/1/2"
    },
    {
      "id": "extension/reattach",
      "entry": "adapters/extension/reattach.sh",
      "kind": "bash",
      "purpose": "Reload a live extension slot in place: re-snapshot dist into the loaded runtime-dist, then reload the extension (service worker + pages) over CDP — no watcher stop, no Chrome kill.",
      "inputs": "--target --cdp-port --watcher-port --start-url --ext-id --dist-dir --settle-ms; env CDP_PORT, WATCHER_PORT, EXTENSION_START_URL, EXT_ID",
      "outputs": "progress on stderr; exit 0/1/2"
    },
    {
      "id": "extension/pin-remote-flags",
      "entry": "adapters/extension/pin-remote-flags.cjs",
      "kind": "lib",
      "purpose": "Pin A/B remote feature-flag variants into an extension manifest _flags before runtime-dist launch.",
      "inputs": "<manifest.json> <KEY=VARIANT[,KEY=VARIANT...]>",
      "outputs": "rewrites manifest._flags.remoteFeatureFlags; exit 0 / throw"
    },
    {
      "id": "extension/readiness",
      "entry": "adapters/extension/readiness.mjs",
      "kind": "node",
      "purpose": "Health probe for one extension instance: dist entry files + live CDP target, repairs <runtime-dir>/extension.id.",
      "inputs": "--target --cdp-port --json; env RECIPE_RUNTIME_DIR",
      "outputs": "readiness report on stdout; exit 0 ready / non-zero"
    },
    {
      "id": "extension/wallet-fixture-state",
      "entry": "adapters/extension/wallet-fixture-state.cjs",
      "kind": "node",
      "purpose": "Instance wallet state: generate deterministic state from a fixture, prefill the Chrome profile, seed/validate over CDP.",
      "inputs": "generate|prefill-profile|seed-cdp + flags per usage(); env RECIPE_RUNTIME_DIR",
      "outputs": "--out/--state JSON files; exit 0/1/2"
    },
    {
      "id": "extension/extension-id",
      "entry": "src/adapters/extension/extension-id.ts",
      "kind": "module",
      "purpose": "Deterministic CRX id resolution from the loaded dist manifest key (TS module used by the runner CLI).",
      "inputs": "resolveExtensionId(target)",
      "outputs": "extension id string"
    },
    {
      "id": "extension/ensure-ready",
      "entry": "src/adapters/extension/ensure-ready.ts",
      "kind": "module",
      "purpose": "Ensure the extension runtime is attachable (TS module used by the runner CLI).",
      "inputs": "ensureExtensionReady(...)",
      "outputs": "readiness result"
    },
    {
      "id": "extension/runtime",
      "entry": "src/adapters/extension/runtime.ts",
      "kind": "module",
      "purpose": "Extension runtime prepare/health over CDP (TS module used by the runner CLI).",
      "inputs": "prepareExtensionRuntime/checkExtensionRuntimeHealth",
      "outputs": "runtime state"
    },
    {
      "id": "extension/runtime-decision",
      "entry": "src/adapters/extension/runtime-decision.ts",
      "kind": "module",
      "purpose": "Cache/deps baseline + readiness decision (TS module used by the runner CLI).",
      "inputs": "decideExtensionReadiness(...)",
      "outputs": "decision record"
    },
    {
      "id": "mobile/runtime-decision",
      "entry": "src/adapters/mobile/runtime-decision.ts",
      "kind": "module",
      "purpose": "Mobile deps + Metro bundle readiness decision (parity with extension runtime-decision).",
      "inputs": "decideMobileReadiness(...)",
      "outputs": "decision record"
    },
    {
      "id": "mobile/deps-markers",
      "entry": "src/adapters/mobile/deps-markers.ts",
      "kind": "module",
      "purpose": "MetaMask Mobile product/native marker tables for harness deps-readiness.",
      "inputs": "mobileProductMarkers(platform?)",
      "outputs": "marker path list"
    },
    {
      "id": "core/inject",
      "entry": "adapters/core/inject.sh",
      "kind": "bash",
      "purpose": "Headless core adapter install: overlay metadata + runner delegate only (no product writes).",
      "inputs": "--target; env RECIPE_HARNESS_ROOT, METAMASK_RUNNER_PROTOCOL_ROOT>FARMSLOT_ROOT",
      "outputs": "<harness>/core/{manifest.json,action-manifest.json,runner/}; exit 0/1/2"
    },
    {
      "id": "core/cleanup",
      "entry": "adapters/core/cleanup.sh",
      "kind": "bash",
      "purpose": "Remove the core overlay dir (idempotent; nothing to restore).",
      "inputs": "--target; env RECIPE_HARNESS_ROOT",
      "outputs": "removes <harness>/core; exit 0/2"
    },
    {
      "id": "lib/harness-path",
      "entry": "adapters/shared/harness-path.sh",
      "kind": "lib",
      "purpose": "THE one sourceable lib: harness root/dir + runtime dir resolution with path validation.",
      "inputs": "env RECIPE_HARNESS_ROOT, RECIPE_RUNTIME_DIR (validated relative paths)",
      "outputs": "harness_root / harness_dir / recipe_runtime_dir functions"
    },
    {
      "id": "lib/hash-helpers",
      "entry": "adapters/shared/hash-helpers.sh",
      "kind": "lib",
      "purpose": "Overlay file hash markers (digest_file/digest_stdin/hash_path) for safe re-install/cleanup.",
      "inputs": "TARGET env var (hash_path)",
      "outputs": "sha256 digests on stdout"
    },
    {
      "id": "lib/json-field",
      "entry": "adapters/shared/json-field.sh",
      "kind": "lib",
      "purpose": "read_runtime_context_field: dotted-path JSON reader for harness scripts.",
      "inputs": "json path + dotted field",
      "outputs": "field value on stdout"
    },
    {
      "id": "lib/tmux-session",
      "entry": "adapters/shared/tmux-session.sh",
      "kind": "lib",
      "purpose": "resolve_run_tmux_session: the explicitly owned tmux session a log-tail window belongs in (RECIPE_TMUX_SESSION -> agentic-runtime.json session; no current-session or slot-number inference).",
      "inputs": "resolve_run_tmux_session [runtime-dir]; env RECIPE_TMUX_SESSION, RECIPE_RUNTIME_CONTEXT",
      "outputs": "resolved session name on stdout (empty when none)"
    },
    {
      "id": "lib/tmux-viewer",
      "entry": "adapters/shared/tmux-viewer.sh",
      "kind": "lib",
      "purpose": "Run-owned tmux log viewer helpers that open, replace, and clean prefixed viewer windows without slot-name inference.",
      "inputs": "tmux_viewer_open/close_marker/sweep_prefix functions; env RECIPE_TMUX_SESSION, RECIPE_RUNTIME_CONTEXT",
      "outputs": "viewer windows and marker files; no-op when no run-owned session is available"
    },
    {
      "id": "lib/activate-repo-node",
      "entry": "adapters/shared/activate-repo-node.sh",
      "kind": "lib",
      "purpose": "Manager-agnostic Node pin from .nvmrc / .tool-versions for non-interactive yarn/webpack spawns (tmux, nohup).",
      "inputs": "activate_repo_node [target-dir]; tries asdf, fnm, mise, nvm, then matching node on PATH",
      "outputs": "REPO_NODE_BIN, REPO_NODE_PATH_PREFIX; prepends bin dir to PATH; exit 0/1/2"
    },
    {
      "id": "lib/activate-repo-ruby",
      "entry": "adapters/shared/activate-repo-ruby.sh",
      "kind": "lib",
      "purpose": "Manager-agnostic Ruby pin from .ruby-version / .tool-versions for iOS pod/gem work in non-interactive spawns; best-effort variant warns + teaches when unresolved.",
      "inputs": "activate_repo_ruby [target-dir] (0/1/2); activate_repo_ruby_best_effort [target-dir]; tries asdf, rbenv, mise, then matching ruby on PATH",
      "outputs": "REPO_RUBY_BIN, REPO_RUBY_PATH_PREFIX; prepends bin dir to PATH"
    },
    {
      "id": "lib/ensure-runner-deps",
      "entry": "adapters/shared/ensure-runner-deps.sh",
      "kind": "lib",
      "purpose": "Idempotent install of runner dependencies from its immutable Yarn lock; isolates runner settings so parent product .yarnrc.yml does not block install.",
      "inputs": "ensure-runner-deps.sh [RUNNER_DIR]; env FARMSLOT_ROOT / METAMASK_RUNNER_PROTOCOL_ROOT optional local link target",
      "outputs": "installed node_modules in RUNNER_DIR; exit 0 when deps ready"
    },
    {
      "id": "lib/runner-deps-ready",
      "entry": "adapters/shared/runner-deps-ready.mjs",
      "kind": "node",
      "purpose": "Validate installed runner dependency versions, accepting only explicit local protocol-root links as development overrides.",
      "inputs": "<runner-dir> [local-protocol-root]",
      "outputs": "exit 0 when dependencies satisfy package.json; exit 1 otherwise"
    },
    {
      "id": "lib/install-repo-deps",
      "entry": "adapters/shared/install-repo-deps.sh",
      "kind": "bash",
      "purpose": "Install a checkout's pinned dependencies through its repository Node toolchain.",
      "inputs": "--target <checkout>",
      "outputs": "corepack yarn install output; exit 0/1/2"
    },
    {
      "id": "lib/resolve-slot-ports",
      "entry": "adapters/shared/resolve-slot-ports.mjs",
      "kind": "node",
      "purpose": "Resolve CDP + watcher ports from the orchestrator's slot-pool JSON by repo path, else 6660+N / 9010+N.",
      "inputs": "resolve-slot-ports.mjs resolve_extension_runtime_ports <repo>",
      "outputs": "CDP_PORT / WATCHER_PORT / SLOT_ID lines on stdout"
    },
    {
      "id": "lib/resolve-slot-ports-core",
      "entry": "adapters/shared/resolve-slot-ports-core.mjs",
      "kind": "lib",
      "purpose": "Self-contained pool/context/formula port resolution imported by the node leaf and TS surface.",
      "inputs": "ESM import from resolve-slot-ports.mjs or resolve-slot-ports.ts",
      "outputs": "resolveSlotPortsByRepo and related functions"
    },
    {
      "id": "lib/recipe-harness-root",
      "entry": "adapters/shared/recipe-harness-root.mjs",
      "kind": "lib",
      "purpose": "Resolve RECIPE_HARNESS_ROOT for overlay node leaves without importing src/paths.ts.",
      "inputs": "ESM import; env RECIPE_HARNESS_ROOT optional override",
      "outputs": "recipeHarnessRoot() relative path string"
    },
    {
      "id": "lib/resolve-slot-ports-sh",
      "entry": "adapters/shared/resolve-slot-ports.sh",
      "kind": "lib",
      "purpose": "Sourced wrapper over resolve-slot-ports.mjs for shell runtime leaves.",
      "inputs": "source + resolve_* / apply_resolved_* function calls",
      "outputs": "KEY=VALUE lines on stdout; env vars via apply_resolved_*"
    },
    {
      "id": "lib/reap-checkout-metros",
      "entry": "adapters/shared/reap-checkout-metros.sh",
      "kind": "lib"
    },
    {
      "id": "lib/sync-wallet-fixture",
      "entry": "adapters/shared/sync-wallet-fixture.sh",
      "kind": "bash",
      "purpose": "Copy wallet fixture to the canonical runtime slot after overlay install.",
      "inputs": "--target <checkout> --slot-id <id> --cdp-port <port>",
      "outputs": "wallet-fixture.json in runtime dir; exit 0 always (non-zero = informational, no source found)"
    },
    {
      "id": "lib/open-log-window",
      "entry": "adapters/shared/open-log-window.sh",
      "kind": "bash",
      "purpose": "(Re)open a read-only tmux tail window for a dev-server log in the run-owned session without touching the process (mm-harness logs --window).",
      "inputs": "--window <name> --log <path> [--runtime-dir <dir>]",
      "outputs": "tmux tail window in the resolved session; exit 0 opened / 1 no session or log / 2 bad args"
    },
    {
      "id": "lib/path-defaults",
      "entry": "adapters/shared/path-defaults.json",
      "kind": "data",
      "purpose": "Single source for the default harness root and runtime dir.",
      "inputs": "none",
      "outputs": "recipeHarnessRoot / recipeRuntimeDir defaults"
    },
    {
      "id": "lib/cli-ux",
      "entry": "adapters/shared/cli-ux.sh",
      "kind": "lib",
      "purpose": "Shared bash UX helpers: progress, log-tui watch, failure playbooks, harness stale warnings.",
      "inputs": "sourced by adapters that invoke recipe CLI commands",
      "outputs": "recipe_progress / recipe_watch_rebuild_log / recipe_failure_playbook functions"
    },
    {
      "id": "lib/log-tui",
      "entry": "adapters/shared/log-tui.mjs",
      "kind": "node",
      "purpose": "Compact build-log UX: last N significant events plus pointer to full log.",
      "inputs": "watch|tail|events --log <path> [--events <n>] [--mode compact|full|quiet] [--json]",
      "outputs": "compact TUI on stderr/stdout; watch exits 0 on success pattern / 1 on failure"
    },
    {
      "id": "lib/open-debug",
      "entry": "adapters/shared/open-debug.mjs",
      "kind": "node",
      "purpose": "Open human-facing debugger UIs for extension CDP or mobile Metro runtimes.",
      "inputs": "--adapter extension|mobile [--cdp-port|--port] [--target page|worker] [--json] [--no-open]",
      "outputs": "debug URL/report on stdout; exit 0/1"
    },
    {
      "id": "lib/harness-source-fingerprint",
      "entry": "adapters/shared/harness-source-fingerprint.mjs",
      "kind": "lib",
      "purpose": "Compute the deterministic source fingerprint stamped into injected extension harness manifests.",
      "inputs": "imported by injection and launch freshness checks",
      "outputs": "stable SHA-256 fingerprint"
    },
    {
      "id": "lib/update-check-worker",
      "entry": "adapters/shared/update-check-worker.mjs",
      "kind": "node",
      "purpose": "Detached, silent registry probe used by the daily passive update notice.",
      "inputs": "<cache-file> <timeout-ms> [registry-endpoint]",
      "outputs": "atomic update-cache refresh; always silent and best-effort"
    },
    {
      "id": "lib/private-atomic-write",
      "entry": "adapters/shared/private-atomic-write.cjs",
      "kind": "lib",
      "purpose": "Publish private setup state through a no-follow temporary file and atomic rename.",
      "inputs": "target path and file bytes on stdin",
      "outputs": "owner-only target file"
    },
    {
      "id": "lib/setup-base",
      "entry": "adapters/shared/setup-base.sh",
      "kind": "lib",
      "purpose": "Bootstrap numbered MetaMask checkouts through the setup-base command.",
      "inputs": "setup-base command arguments",
      "outputs": "numbered checkouts, saved preferences, and run summary"
    }
  ]
}
