#!/usr/bin/env bash
# live.sh — extension launch-then-verify sequencer for one live slot run
# mega-string now decomposed into start-watch.sh / snapshot-dist.sh /
# seed-fixture.sh)
#
# Purpose:
#   Builds the per-run prepare command from the named feature scripts
#   (watch, dist snapshot, fixture seed, detached chrome, CDP poll), then
#   runs launch.sh and, unless --launch-only is set, verify.sh under a
#   timestamped artifact dir.
#
# Inputs (flags / env):
#   --target <metamask-extension> (default $PWD)
#   --cdp-port <port> (optional; inferred from checkout context/pool when omitted)
#   --launch-existing-dist | --start-watch | --build-lavamoat | --prepare-cmd <cmd>
#       (env RECIPE_HARNESS_EXTENSION_LAUNCH_CMD)
#   --launch-only (skip recipe verification; used by fixture application while
#       its checkout lock is held)
#   --dist-dir <rel> (default dist/chrome), --chrome-user-data-dir <dir>,
#   --remote-flag <KEY=VARIANT[,KEY=VARIANT...]> (pins manifest _flags into the
#       ephemeral runtime-dist snapshot before launch; omit for default behavior)
#   --out <recipes-dir>, --artifacts-dir <dir>
#   env RECIPE_HARNESS_CHROME_BIN (validated executable; else Playwright
#   chromium with approval-gated install messaging), RECIPE_WALLET_FIXTURE,
#   RECIPE_HARNESS_LIVE_KEEP (artifact pruning, default 5)
#
# Outputs:
#   <artifacts>/summary.json (adapter/action/status, launch/verify exit
#   codes + child summary paths, easyCommand), <artifacts>/{launch,verify},
#   <artifacts>/logs/fixture-source.json provenance.
#   Exit 0 — launch and verify both passed; 1 — either failed; 2 — bad args.
#
# Never touches: product source files; live artifact dirs newer than the
# pruning window; anything outside the target's harness dir.
set -euo pipefail

TARGET="$PWD"
INVOCATION_DIR="$PWD"
CDP_PORT=""
ARTIFACTS=""
OUT=""
PREPARE_CMD="${RECIPE_HARNESS_EXTENSION_LAUNCH_CMD:-}"
LAUNCH_EXISTING_DIST=false
START_WATCH=false
BUILD_LAVAMOAT=false
EXTERNAL_ARTIFACT=false
ARTIFACT_PROVENANCE=""
RESET_PROFILE=true
DIST_DIR="dist/chrome"
CHROME_USER_DATA_DIR="${CHROME_USER_DATA_DIR:-}"
REMOTE_FLAGS=""
REMOTE_FLAGS_APPLIED=false
RUN_VERIFY=true
while [ "$#" -gt 0 ]; do
  case "$1" in
    --target) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; TARGET="$2"; shift 2 ;;
    --out) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; OUT="$2"; shift 2 ;;
    --cdp-port) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; CDP_PORT="$2"; shift 2 ;;
    --artifacts-dir) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; ARTIFACTS="$2"; shift 2 ;;
    --prepare-cmd) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; PREPARE_CMD="$2"; shift 2 ;;
    --launch-existing-dist) LAUNCH_EXISTING_DIST=true; shift ;;
    --external-artifact) EXTERNAL_ARTIFACT=true; LAUNCH_EXISTING_DIST=true; shift ;;
    --artifact-provenance) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; ARTIFACT_PROVENANCE="$2"; shift 2 ;;
    --preserve-profile) RESET_PROFILE=false; shift ;;
    --start-url) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; START_URL="$2"; shift 2 ;;
    --start-watch|--start-test-watch) START_WATCH=true; LAUNCH_EXISTING_DIST=true; shift ;;
    --build-lavamoat) BUILD_LAVAMOAT=true; LAUNCH_EXISTING_DIST=true; shift ;;
    --launch-only) RUN_VERIFY=false; shift ;;
    --dist-dir) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; DIST_DIR="$2"; shift 2 ;;
    --chrome-user-data-dir) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; CHROME_USER_DATA_DIR="$2"; shift 2 ;;
    --remote-flag) [ "$#" -ge 2 ] || { echo "Missing value for $1" >&2; exit 2; }; REMOTE_FLAGS="$2"; shift 2 ;;
    -h|--help) echo "Usage: live.sh [--target <metamask-extension>] [--out <recipes-dir>] [--cdp-port <port>] [--launch-existing-dist|--start-watch|--build-lavamoat|--external-artifact --dist-dir <absolute-dir> --artifact-provenance <absolute-file> [--preserve-profile]|--prepare-cmd <cmd>] [--launch-only] [--dist-dir dist/chrome] [--remote-flag KEY=VARIANT] [--artifacts-dir <dir>]"; exit 0 ;;
    *) echo "Unknown arg: $1" >&2; exit 2 ;;
  esac
done

if $BUILD_LAVAMOAT && $START_WATCH; then
  echo "--build-lavamoat cannot be combined with --start-watch" >&2
  exit 2
fi
if $EXTERNAL_ARTIFACT && { $BUILD_LAVAMOAT || $START_WATCH || [ -n "$REMOTE_FLAGS" ]; }; then
  echo "--external-artifact cannot be combined with build, watch, or remote-flag options" >&2
  exit 2
fi
if $EXTERNAL_ARTIFACT && [ ! -f "$ARTIFACT_PROVENANCE" ]; then
  echo "--external-artifact requires --artifact-provenance <file>" >&2
  exit 2
fi
if ! $RESET_PROFILE && ! $EXTERNAL_ARTIFACT; then
  echo "--preserve-profile is only valid for a verified external artifact" >&2
  exit 2
fi
if $EXTERNAL_ARTIFACT; then
  case "$ARTIFACT_PROVENANCE" in
    /*) ;;
    *) echo "--artifact-provenance must be an absolute file path" >&2; exit 2 ;;
  esac
fi

case "$CHROME_USER_DATA_DIR" in
  ""|/*) ;;
  *) CHROME_USER_DATA_DIR="$INVOCATION_DIR/$CHROME_USER_DATA_DIR" ;;
esac

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
for _hp in "$SCRIPT_DIR/lib/harness-path.sh" "$SCRIPT_DIR/../shared/harness-path.sh"; do
  [ -f "$_hp" ] && { . "$_hp"; break; }
done
unset _hp
if ! command -v harness_root >/dev/null 2>&1; then
  echo "mm-harness: shared lib adapters/shared/harness-path.sh not found; reinstall the runner." >&2
  exit 1
fi
TARGET="$(cd "$TARGET" && pwd)"
# Infer checkout-scoped CDP when omitted (context → pool → formula).
if [ -z "$CDP_PORT" ]; then
  for _rsp in "$SCRIPT_DIR/lib/resolve-slot-ports.sh" "$SCRIPT_DIR/../shared/resolve-slot-ports.sh"; do
    [ -f "$_rsp" ] && { # shellcheck disable=SC1090
      . "$_rsp"; break; }
  done
  unset _rsp
  if command -v apply_extension_slot_ports >/dev/null 2>&1; then
    apply_extension_slot_ports "$TARGET"
  fi
fi
[ -n "$CDP_PORT" ] || { echo "Could not infer extension CDP port for $TARGET; pass --cdp-port or prepare the slot." >&2; exit 2; }
# Reject a non-numeric port before it is interpolated into the Chrome launch
# command and the CDP HTTP probes.
case "$CDP_PORT" in
  *[!0-9]*) echo "Invalid --cdp-port (must be numeric): $CDP_PORT" >&2; exit 2 ;;
esac

# verify.sh is a recipe-tree feature: co-located in installed copies, under
# adapters/extension in a repo checkout.
VERIFY_SH=""
for _v in "$SCRIPT_DIR/verify.sh" "$SCRIPT_DIR/../../adapters/extension/verify.sh"; do
  [ -f "$_v" ] && { VERIFY_SH="$_v"; break; }
done
unset _v
if [ -z "$VERIFY_SH" ]; then
  echo "mm-harness: extension verify.sh not found next to $SCRIPT_DIR; reinstall the runner." >&2
  exit 1
fi
RUNTIME_DIR="$(recipe_runtime_dir)"
RUNTIME_DIST_DIR="${RECIPE_RUNTIME_DIST_DIR:-runtime-dist}"
case "$RUNTIME_DIST_DIR" in
  ""|.|..|*/*|*[!A-Za-z0-9._-]*)
    echo "RECIPE_RUNTIME_DIST_DIR must be one safe directory name: '$RUNTIME_DIST_DIR'" >&2
    exit 2
    ;;
esac
CHROME_PROFILE_NAME="${RECIPE_CHROME_PROFILE_NAME:-chrome-profile}"
# Runner bin (installed wrapper → source runner). Used by the watch prepare path
# to defer the cache-clear DECISION to `runtime-decision` (single source) and to
# record the deps/cache baseline after a confirmed-good build.
RUNNER_BIN="$(harness_dir "$TARGET" extension)/runner/bin/mm-harness"
OUT="${OUT:-$(harness_root)/extension/runner/recipes}"
ARTIFACTS="${ARTIFACTS:-$(harness_dir "$TARGET" extension)/live/$(date -u +%Y%m%dT%H%M%SZ)}"
mkdir -p "$ARTIFACTS/logs"

# Prune stale live artifact dirs (configurable harness root, not a hardcoded path)
# so old runtime-dist snapshots can't be loaded and don't accumulate to GBs.
# Keep the most recent few; override count with RECIPE_HARNESS_LIVE_KEEP.
LIVE_ROOT="$(harness_dir "$TARGET" extension)/live"
LIVE_KEEP="${RECIPE_HARNESS_LIVE_KEEP:-5}"
# Must be a positive integer: a non-numeric value would break the arithmetic and a
# 0 would `tail -n +1` and delete every dir including this run's fresh $ARTIFACTS.
case "$LIVE_KEEP" in ''|*[!0-9]*) LIVE_KEEP=5 ;; esac
[ "$LIVE_KEEP" -ge 1 ] 2>/dev/null || LIVE_KEEP=5
if [ -d "$LIVE_ROOT" ]; then
  # `|| true`: an empty live/ (no child dirs) makes ls exit non-zero, which would
  # abort the script under `set -euo pipefail`. Pruning is best-effort.
  ls -1dt "$LIVE_ROOT"/*/ 2>/dev/null | tail -n "+$((LIVE_KEEP + 1))" | while IFS= read -r _old; do rm -rf "$_old"; done || true
fi

if $LAUNCH_EXISTING_DIST && [ -z "$PREPARE_CMD" ]; then
  if $EXTERNAL_ARTIFACT; then
    case "$DIST_DIR" in
      /*) DIST_ABS="$DIST_DIR" ;;
      *) echo "--external-artifact requires an absolute --dist-dir" >&2; exit 2 ;;
    esac
  else
    DIST_ABS="$TARGET/$DIST_DIR"
  fi
  # Stable beside the profile: the reused profile registers the unpacked
  # extension by PATH; a per-run snapshot path gets pruned and the next launch
  # loads nothing ("No EIP-6963 Provider Detected").
  RUNTIME_ROOT_ABS="$TARGET/$RUNTIME_DIR"
  RUNTIME_DIST_ABS="$RUNTIME_ROOT_ABS/$RUNTIME_DIST_DIR"
  # Stable per-checkout profile: successive runs recognize their own Chrome
  # (ownership guard matches on --user-data-dir), take it over cleanly, and the
  # seeded wallet persists across relaunches. A per-run profile made every
  # relaunch "foreign" and let live/ pruning delete profiles still in use.
  PROFILE_ABS="${CHROME_USER_DATA_DIR:-$TARGET/$RUNTIME_DIR/$CHROME_PROFILE_NAME}"
  case "$PROFILE_ABS" in
    "$TARGET/$RUNTIME_DIR/"*) ;;
    *) echo "--chrome-user-data-dir must be a dedicated child of $TARGET/$RUNTIME_DIR" >&2; exit 2 ;;
  esac
  FIXTURE_STATE_ABS="$ARTIFACTS/fixture-state.json"
  FIXTURE_VALIDATION_ABS="$ARTIFACTS/logs/fixture-account-parity.json"
  WALLET_FIXTURE_ABS=""
  if ! $EXTERNAL_ARTIFACT; then
    # Wallet fixture resolution chain + provenance live in seed-fixture.sh.
    WALLET_FIXTURE_ABS="$(bash "$SCRIPT_DIR/seed-fixture.sh" resolve --target "$TARGET" --cdp-port "$CDP_PORT" --source-out "$ARTIFACTS/logs/fixture-source.json")"
  fi
  if ! $EXTERNAL_ARTIFACT && [ ! -f "$ARTIFACTS/logs/fixture-source.json" ]; then
    # resolve failed before writing provenance (invalid RECIPE_WALLET_FIXTURE);
    # keep the documented missing-provenance artifact.
    node - "$ARTIFACTS/logs/fixture-source.json" "" <<'NODE'
const fs = require('fs');
const [out, fixture] = process.argv.slice(2);
fs.mkdirSync(require('path').dirname(out), { recursive: true });
fs.writeFileSync(out, `${JSON.stringify({
  status: fixture ? 'present' : 'missing',
  fixturePath: fixture || null,
  generatedAt: new Date().toISOString(),
}, null, 2)}\n`);
NODE
  fi
  mkdir -p "$PROFILE_ABS"
  quoted_dist="$(printf '%q' "$DIST_ABS")"
  quoted_runtime_root="$(printf '%q' "$RUNTIME_ROOT_ABS")"
  quoted_runtime_dist="$(printf '%q' "$RUNTIME_DIST_ABS")"
  quoted_profile="$(printf '%q' "$PROFILE_ABS")"
  quoted_seed_fixture="$(printf '%q' "$SCRIPT_DIR/seed-fixture.sh")"
  quoted_start_watch="$(printf '%q' "$SCRIPT_DIR/start-watch.sh")"
  quoted_build_lavamoat="$(printf '%q' "$SCRIPT_DIR/build-lavamoat.sh")"
  quoted_snapshot_dist="$(printf '%q' "$SCRIPT_DIR/snapshot-dist.sh")"
  quoted_configure_manifest="$(printf '%q' "$SCRIPT_DIR/configure-runtime-manifest.cjs")"
  quoted_check_infura="$(printf '%q' "$SCRIPT_DIR/check-infura-readiness.cjs")"
  quoted_stamp_title="$(printf '%q' "$SCRIPT_DIR/stamp-runtime-title.cjs")"
  quoted_chrome_launcher="$(printf '%q' "$SCRIPT_DIR/launch-browser.cjs")"
  quoted_artifact_state="$(printf '%q' "$SCRIPT_DIR/artifact-runtime-state.cjs")"
  quoted_fixture_state="$(printf '%q' "$FIXTURE_STATE_ABS")"
  quoted_fixture_validation="$(printf '%q' "$FIXTURE_VALIDATION_ABS")"
  quoted_extension_id_file="$(printf '%q' "$TARGET/$RUNTIME_DIR/extension.id")"
  quoted_target="$(printf '%q' "$TARGET")"
  quoted_runner="$(printf '%q' "$RUNNER_BIN")"
  quoted_runtime_dir="$(printf '%q' "$RUNTIME_DIR")"
  if [ -n "${RECIPE_HARNESS_CHROME_BIN:-}" ]; then
    CHROME_BIN="$RECIPE_HARNESS_CHROME_BIN"
    if [ ! -f "$CHROME_BIN" ] || [ ! -x "$CHROME_BIN" ]; then
      echo "[recipe-harness] RECIPE_HARNESS_CHROME_BIN is not an executable file: $CHROME_BIN" >&2
      exit 1
    fi
  fi

  if [ -z "${CHROME_BIN:-}" ]; then
    # bash 3.2 (macOS /bin/bash) mis-parses heredocs inside $(...): its scanner
    # trips on quotes/backticks in the JS. Write the probe to a temp file and
    # command-substitute a plain `node` invocation instead.
    _chrome_probe="$(mktemp -t chrome-probe-XXXXXX)"
    cat > "$_chrome_probe" <<'NODE'
const fs = require('fs');
const path = require('path');
const { createRequire } = require('module');
const requireFromTarget = createRequire(path.join(process.cwd(), 'package.json'));

let chromium = null;
function shellQuote(value) {
  return `'${String(value).replace(/'/g, `'\\''`)}'`;
}
for (const pkg of ['@playwright/test', 'playwright']) {
  try {
    chromium = requireFromTarget(pkg).chromium;
    if (chromium) break;
  } catch (_error) {
    // Optional Playwright package unavailable; try the next package name.
  }
}
if (!chromium) {
  console.error('[recipe-harness] Playwright is not available from this checkout; install dependencies first, or set RECIPE_HARNESS_CHROME_BIN to an explicitly approved browser.');
  process.exit(1);
}

let executable = '';
try {
  executable = chromium.executablePath();
} catch (error) {
  const message = error && error.message ? error.message : String(error);
  console.error(`[recipe-harness] Could not resolve Playwright Chromium executable: ${message}. Manual approval required before installing the Playwright Chromium browser cache (no package.json changes); ask the user before running yarn playwright install chromium.`);
  process.exit(1);
}
if (!fs.existsSync(executable)) {
  console.error(`[recipe-harness] Playwright Chromium is not installed at ${executable}. Manual approval required before installing the Playwright Chromium browser cache (no package.json changes). Ask the user for approval; if they agree, run: cd ${shellQuote(process.cwd())} && yarn playwright install chromium`);
  console.error('[recipe-harness] To use a browser that is already installed, set RECIPE_HARNESS_CHROME_BIN=/path/to/chrome explicitly.');
  process.exit(1);
}

process.stdout.write(executable);
NODE
    CHROME_PROBE_LOG="$ARTIFACTS/logs/chrome-probe.log"
    CHROME_BIN="$(cd "$TARGET" && node "$_chrome_probe" 2>"$CHROME_PROBE_LOG" || true)"
    rm -f "$_chrome_probe"
  fi

  if [ -z "${CHROME_BIN:-}" ]; then
    [ -n "${CHROME_PROBE_LOG:-}" ] && cat "$CHROME_PROBE_LOG" >&2 2>/dev/null || true
    echo "[recipe-harness] No compatible Chromium binary selected; stopping before build or live Extension launch." >&2
    exit 1
  fi
  quoted_chrome="$(printf '%q' "$CHROME_BIN")"
  quoted_chrome_log="$(printf '%q' "$ARTIFACTS/logs/chrome.log")"
  quoted_chrome_pid="$(printf '%q' "$ARTIFACTS/logs/chrome.pid")"
  prepare_parts=()
  if $EXTERNAL_ARTIFACT; then
    quoted_artifact_provenance="$(printf '%q' "$ARTIFACT_PROVENANCE")"
  else
    node "$SCRIPT_DIR/artifact-runtime-state.cjs" clear --target "$TARGET" --runtime-dir "$RUNTIME_DIR"
  fi
  if $START_WATCH; then
    prepare_parts+=("bash ${quoted_start_watch} --runtime-dir ${quoted_runtime_dir} --runner-bin ${quoted_runner}")
  fi
  if $BUILD_LAVAMOAT; then
    prepare_parts+=("bash ${quoted_build_lavamoat} --target ${quoted_target} --runtime-dir ${quoted_runtime_dir}")
  fi
  if ! $EXTERNAL_ARTIFACT; then
    prepare_parts+=("node ${quoted_check_infura} --target ${quoted_target} --runtime-dist ${quoted_dist}")
  fi
  if $EXTERNAL_ARTIFACT; then
    prepare_parts+=("bash ${quoted_snapshot_dist} --dist ${quoted_dist} --target ${quoted_target} --runtime-root ${quoted_runtime_root} --runtime-dist ${quoted_runtime_dist} --exact")
  else
    prepare_parts+=("bash ${quoted_snapshot_dist} --dist ${quoted_dist} --target ${quoted_target} --runtime-root ${quoted_runtime_root} --runtime-dist ${quoted_runtime_dist}")
  fi
  if $EXTERNAL_ARTIFACT; then
    prepare_parts+=("node ${quoted_artifact_state} set --target ${quoted_target} --runtime-dir ${quoted_runtime_dir} --source-dir ${quoted_dist} --runtime-dist ${quoted_runtime_dist} --provenance ${quoted_artifact_provenance} --chrome-user-data-dir ${quoted_profile}")
  fi
  if ! $EXTERNAL_ARTIFACT; then
    prepare_parts+=("node ${quoted_configure_manifest} --target ${quoted_target} --manifest ${quoted_runtime_dist}/manifest.json")
  fi
  reset_profile_arg=""
  $RESET_PROFILE && reset_profile_arg=" --reset-profile 1"
  prepare_parts+=("node ${quoted_chrome_launcher} --stop-only 1${reset_profile_arg} --chrome-bin ${quoted_chrome} --profile ${quoted_profile} --cdp-port ${CDP_PORT} --extension-dir ${quoted_runtime_dist} --chrome-log ${quoted_chrome_log} --chrome-pid ${quoted_chrome_pid}")
  if ! $EXTERNAL_ARTIFACT; then
    prepare_parts+=("node ${quoted_stamp_title} --target ${quoted_target} --runtime-dist ${quoted_runtime_dist} --runtime-dir ${quoted_runtime_dir}")
  fi
  # Optional A/B feature-flag pinning: patch the ephemeral snapshot manifest so
  # manifest._flags wins over the fetched ClientConfigApi value. No-op unless
  # --remote-flag was passed; the snapshot is re-created each run, so no revert.
  if [ -n "$REMOTE_FLAGS" ]; then
    quoted_pin_flags="$(printf '%q' "$SCRIPT_DIR/pin-remote-flags.cjs")"
    quoted_remote_flags="$(printf '%q' "$REMOTE_FLAGS")"
    quoted_runtime_manifest="$(printf '%q' "$RUNTIME_DIST_ABS/manifest.json")"
    prepare_parts+=("node ${quoted_pin_flags} ${quoted_runtime_manifest} ${quoted_remote_flags}")
    REMOTE_FLAGS_APPLIED=true
  fi
  if [ -n "$WALLET_FIXTURE_ABS" ]; then
    quoted_wallet_fixture="$(printf '%q' "$WALLET_FIXTURE_ABS")"
    prepare_parts+=("bash ${quoted_seed_fixture} prefill --target ${quoted_target} --fixture ${quoted_wallet_fixture} --state ${quoted_fixture_state} --profile ${quoted_profile} --extension-dir ${quoted_runtime_dist} --extension-id-file ${quoted_extension_id_file}")
  fi
  chrome_launch_cmd="node ${quoted_chrome_launcher} --chrome-bin ${quoted_chrome} --profile ${quoted_profile} --cdp-port ${CDP_PORT} --extension-dir ${quoted_runtime_dist} --chrome-log ${quoted_chrome_log} --chrome-pid ${quoted_chrome_pid}"
  if [ -n "${START_URL:-}" ]; then
    chrome_launch_cmd="$chrome_launch_cmd --start-url $(printf '%q' "$START_URL")"
  fi
  prepare_parts+=("$chrome_launch_cmd")
  prepare_parts+=("for i in {1..60}; do curl -fsS --max-time 1 http://127.0.0.1:${CDP_PORT}/json/version >/dev/null 2>&1 && break; sleep 1; done; curl -fsS --max-time 1 http://127.0.0.1:${CDP_PORT}/json/version >/dev/null")
  if [ -n "$WALLET_FIXTURE_ABS" ]; then
    prepare_parts+=("bash ${quoted_seed_fixture} seed-cdp --target ${quoted_target} --fixture ${quoted_wallet_fixture} --state ${quoted_fixture_state} --cdp-port ${CDP_PORT} --extension-dir ${quoted_runtime_dist} --extension-id-file ${quoted_extension_id_file} --out ${quoted_fixture_validation}")
  fi
  PREPARE_CMD="set -euo pipefail; $(IFS='; '; printf '%s' "${prepare_parts[*]}")"
fi

if [ -n "$REMOTE_FLAGS" ] && [ "$REMOTE_FLAGS_APPLIED" != "true" ]; then
  echo "[recipe-harness] WARN: --remote-flag '$REMOTE_FLAGS' had no effect: flag pinning only applies to the snapshot launch path (--launch-existing-dist/--start-watch/--build-lavamoat without a custom --prepare-cmd)." >&2
fi

echo "Extension live validation command:"
display_args=(mm-harness runtime-launch --adapter extension --target "$TARGET" --cdp-port "$CDP_PORT")
$START_WATCH && display_args+=(--start-watch)
$BUILD_LAVAMOAT && display_args+=(--build-lavamoat)
$EXTERNAL_ARTIFACT && display_args+=(--external-artifact --dist-dir "$DIST_DIR" --artifact-provenance "$ARTIFACT_PROVENANCE")
$RESET_PROFILE || display_args+=(--preserve-profile)
[ -n "$REMOTE_FLAGS" ] && display_args+=(--remote-flag "$REMOTE_FLAGS")
[ -n "$CHROME_USER_DATA_DIR" ] && display_args+=(--chrome-user-data-dir "$CHROME_USER_DATA_DIR")
printf '  '
printf '%q ' "${display_args[@]}"
printf '\n'
echo "Launch artifacts: $ARTIFACTS/launch"
$RUN_VERIFY && echo "Verify artifacts: $ARTIFACTS/verify"

launch_args=(--target "$TARGET" --cdp-port "$CDP_PORT" --artifacts-dir "$ARTIFACTS/launch")
[ -n "$PREPARE_CMD" ] && launch_args+=(--prepare-cmd "$PREPARE_CMD")

echo "[recipe-harness] phase 1/2: launch (prepare + CDP readiness)" >&2
set +e
"$SCRIPT_DIR/launch.sh" "${launch_args[@]}"
launch_status=$?
set -e

verify_status=0
if [ "$launch_status" -eq 0 ] && $RUN_VERIFY; then
  echo "[recipe-harness] phase 2/2: live verify (readiness + smoke recipe)" >&2
  set +e
  "$VERIFY_SH" --target "$TARGET" --out "$OUT" --cdp-port "$CDP_PORT" --artifacts-dir "$ARTIFACTS/verify"
  verify_status=$?
  set -e
elif [ "$launch_status" -ne 0 ]; then
  verify_status=1
  echo "Skipping Extension live verify because launch failed; see $ARTIFACTS/launch/summary.json" >&2
else
  echo "Skipping Extension live verify for launch-only fixture application." >&2
fi

TARGET_FOR_SUMMARY="$TARGET" ARTIFACTS_FOR_SUMMARY="$ARTIFACTS" CDP_PORT_FOR_SUMMARY="$CDP_PORT" LAUNCH_STATUS="$launch_status" VERIFY_STATUS="$verify_status" RUN_VERIFY="$RUN_VERIFY" LAUNCH_EXISTING_DIST="$LAUNCH_EXISTING_DIST" START_WATCH="$START_WATCH" BUILD_LAVAMOAT="$BUILD_LAVAMOAT" EXTERNAL_ARTIFACT="$EXTERNAL_ARTIFACT" node <<'NODE'
const fs = require('fs');
const path = require('path');
const artifacts = process.env.ARTIFACTS_FOR_SUMMARY;
const launchSummary = path.join(artifacts, 'launch', 'summary.json');
const verifySummary = path.join(artifacts, 'verify', 'summary.json');
const launchStatus = Number(process.env.LAUNCH_STATUS);
const verifyStatus = Number(process.env.VERIFY_STATUS);
const runVerify = process.env.RUN_VERIFY === 'true';
fs.writeFileSync(path.join(artifacts, 'summary.json'), `${JSON.stringify({
  adapter: 'extension',
  action: 'live',
  status: launchStatus === 0 && verifyStatus === 0 ? 'pass' : 'fail',
  target: process.env.TARGET_FOR_SUMMARY,
  cdpPort: process.env.CDP_PORT_FOR_SUMMARY,
  launchExistingDist: process.env.LAUNCH_EXISTING_DIST === 'true',
  startWatch: process.env.START_WATCH === 'true',
  buildLavaMoat: process.env.BUILD_LAVAMOAT === 'true',
  externalArtifact: process.env.EXTERNAL_ARTIFACT === 'true',
  launch: { exitCode: launchStatus, summaryPath: fs.existsSync(launchSummary) ? launchSummary : null },
  verify: runVerify
    ? { status: verifyStatus === 0 ? 'pass' : 'fail', exitCode: verifyStatus, summaryPath: fs.existsSync(verifySummary) ? verifySummary : null }
    : { status: 'skipped', exitCode: null, summaryPath: null },
  easyCommand: `mm-harness launch --verify --target <repo>`,
  note: runVerify
    ? 'Runs launch then live verify so a developer can validate browser startup, CDP readiness, recipe bridge, screenshots/fallback classification, and sample recipes from one runner-owned command.'
    : 'Runs launch validation only for fixture application while the checkout lock is held.',
  generatedAt: new Date().toISOString(),
}, null, 2)}\n`);
NODE

echo "Extension live validation summary: $ARTIFACTS/summary.json"
[ "$launch_status" -eq 0 ] && [ "$verify_status" -eq 0 ]
