#!/usr/bin/env sh
set -e

SELLABLE_INSTALLER_SCRIPT_VERSION="45.0.0"
DEFAULT_SELLABLE_INSTALL_PACKAGE_SPEC="@sellable/install@latest"
DEFAULT_SELLABLE_MCP_PACKAGE_SPEC="@sellable/mcp@latest"
DEFAULT_SELLABLE_NODE_VERSION="22.16.0"

HOME="$(printenv HOME 2>/dev/null || true)"
PATH="$(printenv PATH 2>/dev/null || true)"
SHELL="$(printenv SHELL 2>/dev/null || true)"
TMPDIR="$(printenv TMPDIR 2>/dev/null || true)"
XDG_STATE_HOME="$(printenv XDG_STATE_HOME 2>/dev/null || true)"
SELLABLE_INSTALL_DIR="$(printenv SELLABLE_INSTALL_DIR 2>/dev/null || true)"
SELLABLE_NODE_DIR="$(printenv SELLABLE_NODE_DIR 2>/dev/null || true)"
SELLABLE_NODE_VERSION="$(printenv SELLABLE_NODE_VERSION 2>/dev/null || true)"
SELLABLE_INSTALL_PACKAGE_SPEC="$(printenv SELLABLE_INSTALL_PACKAGE_SPEC 2>/dev/null || true)"
SELLABLE_MCP_PACKAGE_SPEC="$(printenv SELLABLE_MCP_PACKAGE_SPEC 2>/dev/null || true)"
SELLABLE_INSTALL_NODE_BIN="$(printenv SELLABLE_INSTALL_NODE_BIN 2>/dev/null || true)"
SELLABLE_INSTALL_NPM_COMMAND="$(printenv SELLABLE_INSTALL_NPM_COMMAND 2>/dev/null || true)"
SELLABLE_INSTALL_NPM_CMD_COMMAND="$(printenv SELLABLE_INSTALL_NPM_CMD_COMMAND 2>/dev/null || true)"
SELLABLE_INSTALLER_HOST="$(printenv SELLABLE_INSTALLER_HOST 2>/dev/null || true)"
SELLABLE_CONFIG_PATH="$(printenv SELLABLE_CONFIG_PATH 2>/dev/null || true)"
SELLABLE_CONFIGS_DIR="$(printenv SELLABLE_CONFIGS_DIR 2>/dev/null || true)"
SELLABLE_INSTALLER_SKIP_VERIFY="$(printenv SELLABLE_INSTALLER_SKIP_VERIFY 2>/dev/null || true)"
SELLABLE_INSTALLER_SKIP_PATH_UPDATE="$(printenv SELLABLE_INSTALLER_SKIP_PATH_UPDATE 2>/dev/null || true)"
SELLABLE_INSTALLER_MODE="$(printenv SELLABLE_INSTALLER_MODE 2>/dev/null || true)"
SELLABLE_INSTALLER_FORCE_UNSUPPORTED="$(printenv SELLABLE_INSTALLER_FORCE_UNSUPPORTED 2>/dev/null || true)"
HTTP_PROXY="$(printenv HTTP_PROXY 2>/dev/null || true)"
HTTPS_PROXY="$(printenv HTTPS_PROXY 2>/dev/null || true)"
NO_PROXY="$(printenv NO_PROXY 2>/dev/null || true)"
http_proxy="$(printenv http_proxy 2>/dev/null || true)"
https_proxy="$(printenv https_proxy 2>/dev/null || true)"
no_proxy="$(printenv no_proxy 2>/dev/null || true)"

if [ -z "$TMPDIR" ]; then
  TMPDIR="/tmp"
fi
if [ -z "$PATH" ]; then
  PATH="/usr/local/bin:/usr/bin:/bin"
fi

NPM_CONFIG_UPDATE_NOTIFIER=false
NPM_CONFIG_FUND=false
NPM_CONFIG_AUDIT=false
NO_UPDATE_NOTIFIER=1
export NPM_CONFIG_UPDATE_NOTIFIER NPM_CONFIG_FUND NPM_CONFIG_AUDIT NO_UPDATE_NOTIFIER

set -u

log() {
  printf '%s\n' "sellable-install: $*"
}

warn() {
  printf '%s\n' "sellable-install: warning: $*" >&2
}

die() {
  printf '%s\n' "sellable-install: error: $*" >&2
  exit 1
}

redact() {
  printf '%s' "$1" | sed -E 's#(https?://[^:/[:space:]]+:)[^@/[:space:]]+@#\1[redacted]@#g; s#(Bearer )[A-Za-z0-9._-]+#\1[redacted]#g; s#skt_(live|test|dev)_[A-Za-z0-9_-]+#[redacted-token]#g'
}

have() {
  command -v "$1" >/dev/null 2>&1
}

run_apk_add_node() {
  if [ "$(id -u 2>/dev/null || printf 1)" = 0 ]; then
    apk add --no-cache nodejs npm
    return
  fi
  if have sudo; then
    sudo -n apk add --no-cache nodejs npm
    return
  fi
  die "Alpine/musl needs Node >=20. Re-run as root, install sudo, or install nodejs+npm before running Sellable."
}

need_home_or_install_dir() {
  if [ -z "$HOME" ] && [ -z "$SELLABLE_INSTALL_DIR" ]; then
    die "HOME is unset. Set HOME or SELLABLE_INSTALL_DIR before running this installer."
  fi
}

detect_os() {
  raw_os="$(uname -s 2>/dev/null || printf unknown)"
  case "$raw_os" in
    Darwin) printf darwin ;;
    Linux) printf linux ;;
    MINGW*|MSYS*|CYGWIN*) printf msys ;;
    *) printf unknown ;;
  esac
}

detect_arch() {
  raw_arch="$(uname -m 2>/dev/null || printf unknown)"
  case "$raw_arch" in
    x86_64|amd64) printf x64 ;;
    arm64|aarch64) printf arm64 ;;
    *) printf unknown ;;
  esac
}

detect_libc() {
  if [ "$(detect_os)" != linux ]; then
    printf none
    return
  fi
  if have ldd && ldd --version 2>&1 | grep -qi musl; then
    printf musl
    return
  fi
  if ls /lib/ld-musl-* >/dev/null 2>&1 || ls /usr/lib/ld-musl-* >/dev/null 2>&1; then
    printf musl
    return
  fi
  printf glibc
}

node_major() {
  node -p 'Number(process.versions.node.split(".")[0])' 2>/dev/null || printf 0
}

have_compatible_node_stack() {
  have node || return 1
  have npm || return 1
  major="$(node_major)"
  [ "$major" -ge 20 ] 2>/dev/null
}

download_file() {
  url="$1"
  dest="$2"
  if have curl; then
    curl -fL --retry 2 --connect-timeout 20 "$url" -o "$dest"
    return
  fi
  if have wget; then
    wget -O "$dest" "$url"
    return
  fi
  die "curl or wget is required to download Node. Install curl/ca-certificates or use the Windows PowerShell route: https://app.sellable.dev/api/v2/cli/install.ps1"
}

write_state() {
  name="$1"
  value="$2"
  mkdir -p "$STATE_ROOT"
  printf '%s\n' "$value" > "$STATE_ROOT/$name"
}

profile_file() {
  if [ -z "$HOME" ]; then
    printf ''
    return
  fi
  shell_name="$(detect_login_shell)"
  case "$shell_name" in
    zsh) printf '%s\n' "$HOME/.zshenv" ;;
    bash) printf '%s\n' "$HOME/.bash_profile" ;;
    fish) printf '%s\n' "$HOME/.config/fish/config.fish" ;;
    *) printf '%s\n' "$HOME/.profile" ;;
  esac
}

detect_login_shell() {
  detected_shell=""
  if have getent && have id; then
    detected_shell="$(getent passwd "$(id -un)" 2>/dev/null | awk -F: '{print $7}' || true)"
  fi
  if [ -z "$detected_shell" ] && have dscl && have id; then
    detected_shell="$(dscl . -read "/Users/$(id -un)" UserShell 2>/dev/null | awk '{print $2}' || true)"
  fi
  if [ -z "$detected_shell" ] && [ -n "$SHELL" ]; then
    detected_shell="$SHELL"
  fi
  if [ -z "$detected_shell" ]; then
    detected_shell="/bin/sh"
  fi
  printf '%s' "$detected_shell" | sed 's#.*/##'
}

profile_path_line() {
  shell_name="$(detect_login_shell)"
  case "$shell_name" in
    fish)
      printf 'set -gx PATH "%s" "%s" $PATH' "$INSTALL_DIR" "$SELLABLE_INSTALL_NODE_BIN"
      ;;
    *)
      printf 'export PATH="%s:%s:$PATH"' "$INSTALL_DIR" "$SELLABLE_INSTALL_NODE_BIN"
      ;;
  esac
}

remove_path_markers_from_profile() {
  marker_file="$1"
  [ -f "$marker_file" ] || return 0
  start_marker="# >>> sellable installer path >>>"
  end_marker="# <<< sellable installer path <<<"
  tmp="$marker_file.sellable.tmp"
  awk -v start="$start_marker" -v end="$end_marker" '
    $0 == start { skipping=1; next }
    $0 == end { skipping=0; next }
    skipping != 1 { print }
  ' "$marker_file" > "$tmp" && mv "$tmp" "$marker_file"
}

remove_stale_path_markers() {
  [ -n "$HOME" ] || return 0
  for marker_file in \
    "$HOME/.profile" \
    "$HOME/.bash_profile" \
    "$HOME/.bashrc" \
    "$HOME/.zshenv" \
    "$HOME/.zprofile" \
    "$HOME/.config/fish/config.fish"
  do
    remove_path_markers_from_profile "$marker_file" || warn "could not update stale Sellable PATH marker in $marker_file"
  done
}

update_path_profile() {
  if [ "$SELLABLE_INSTALLER_SKIP_PATH_UPDATE" = 1 ]; then
    warn "skipping profile PATH update because SELLABLE_INSTALLER_SKIP_PATH_UPDATE=1"
    return
  fi
  pf="$(profile_file)"
  if [ -z "$pf" ]; then
    warn "HOME is unset, so no shell profile PATH marker was written"
    return
  fi
  mkdir -p "$(dirname "$pf")" 2>/dev/null || {
    warn "could not create profile directory for $pf"
    warn "To persist PATH manually: $(profile_path_line)"
    return
  }
  touch "$pf" 2>/dev/null || {
    warn "profile $pf is not writable; add $INSTALL_DIR to PATH manually"
    warn "To persist PATH manually: $(profile_path_line)"
    return
  }
  remove_stale_path_markers
  start_marker="# >>> sellable installer path >>>"
  end_marker="# <<< sellable installer path <<<"
  path_line="$(profile_path_line)"
  tmp="$pf.sellable.tmp"
  {
    cat "$pf"
    printf '\n%s\n%s\n%s\n' "$start_marker" "$path_line" "$end_marker"
  } > "$tmp" && mv "$tmp" "$pf"
}

install_node_runtime() {
  os="$1"
  arch="$2"
  libc="$3"

  if [ "$os" = msys ]; then
    die "Node/npm were not found in Git Bash/MSYS. Install Node for Windows or run: powershell -NoProfile -ExecutionPolicy Bypass -Command \"irm https://app.sellable.dev/api/v2/cli/install.ps1 | iex\""
  fi
  if [ "$os" = unknown ] || [ "$arch" = unknown ]; then
    die "unsupported platform: os=$os arch=$arch"
  fi
  if [ "$os" = linux ] && [ "$libc" = musl ]; then
    have apk || die "Alpine/musl needs apk so the installer can install nodejs+npm. Install Node >=20 first or use a Debian/Ubuntu image."
    log "installing Node/npm with apk for Alpine/musl"
    run_apk_add_node
    have_compatible_node_stack || die "apk nodejs+npm did not provide Node >=20 with npm"
    write_state ".node-version" "$(node -v) apk $(command -v node)"
    return
  fi
  have tar || die "tar is required to install local Node"

  version="$SELLABLE_NODE_VERSION"
  if [ -z "$version" ]; then
    version="$DEFAULT_SELLABLE_NODE_VERSION"
  fi
  if [ -z "$SELLABLE_NODE_DIR" ]; then
    NODE_DIR="$STATE_ROOT/node-v$version-$os-$arch"
  else
    NODE_DIR="$SELLABLE_NODE_DIR"
  fi
  NODE_CURRENT_DIR="$STATE_ROOT/node-current"

  if [ -x "$NODE_DIR/bin/node" ]; then
    export PATH="$NODE_DIR/bin:$PATH"
    log "using cached Node $(node -v) from $NODE_DIR"
    write_state ".node-version" "$(node -v) cached $NODE_DIR"
    ln -sfn "$NODE_DIR" "$NODE_CURRENT_DIR" 2>/dev/null || true
    return
  fi

  case "$os" in
    linux)
      ext="tar.xz"
      have xz || die "xz is required to extract Node on Linux. Install xz-utils or xz."
      ;;
    darwin)
      ext="tar.gz"
      ;;
    *)
      die "unsupported Node bootstrap platform: $os"
      ;;
  esac

  node_pkg="node-v$version-$os-$arch"
  url="https://nodejs.org/dist/v$version/$node_pkg.$ext"
  downloads="$STATE_ROOT/downloads"
  mkdir -p "$downloads"
  archive="$downloads/$node_pkg.$ext"
  tmp_extract="$STATE_ROOT/node-extract-$node_pkg"

  log "downloading Node v$version for $os/$arch"
  download_file "$url" "$archive"
  rm -rf "$tmp_extract"
  mkdir -p "$tmp_extract"
  tar -xf "$archive" -C "$tmp_extract"
  rm -rf "$NODE_DIR"
  mv "$tmp_extract/$node_pkg" "$NODE_DIR"
  rm -rf "$tmp_extract"
  ln -sfn "$NODE_DIR" "$NODE_CURRENT_DIR" 2>/dev/null || true
  export PATH="$NODE_DIR/bin:$PATH"

  have_compatible_node_stack || die "downloaded Node runtime did not provide Node >=20 with npm"
  write_state ".node-version" "$(node -v) bootstrapped $NODE_DIR"
}

print_proxy_state() {
  for var in HTTP_PROXY HTTPS_PROXY NO_PROXY http_proxy https_proxy no_proxy; do
    eval "value=\$$var"
    if [ -n "$value" ]; then
      log "$var=$(redact "$value")"
    fi
  done
  if have npm; then
    npm_proxy="$(npm config get proxy 2>/dev/null || true)"
    npm_https_proxy="$(npm config get https-proxy 2>/dev/null || true)"
    if [ -n "$npm_proxy" ] && [ "$npm_proxy" != null ]; then
      log "npm proxy=$(redact "$npm_proxy")"
    fi
    if [ -n "$npm_https_proxy" ] && [ "$npm_https_proxy" != null ]; then
      log "npm https-proxy=$(redact "$npm_https_proxy")"
    fi
  fi
}

resolve_node_bin() {
  node_path="$(command -v node 2>/dev/null || true)"
  if [ -n "$node_path" ]; then
    dirname "$node_path"
  fi
}

resolve_npm_command() {
  node_bin="$1"
  if [ -n "$node_bin" ]; then
    for name in npm npm.cmd; do
      candidate="$node_bin/$name"
      if [ -f "$candidate" ] || [ -x "$candidate" ]; then
        printf '%s\n' "$candidate"
        return
      fi
    done
  fi
  for name in npm npm.cmd; do
    candidate="$(command -v "$name" 2>/dev/null || true)"
    case "$candidate" in
      *node_modules/.bin/*) continue ;;
    esac
    if [ -n "$candidate" ]; then
      printf '%s\n' "$candidate"
      return
    fi
  done
  for name in npm npm.cmd; do
    candidate="$(command -v "$name" 2>/dev/null || true)"
    if [ -n "$candidate" ]; then
      printf '%s\n' "$candidate"
      return
    fi
  done
}

resolve_npm_cmd_command() {
  node_bin="$1"
  if [ -n "$node_bin" ]; then
    for name in npm.cmd npm; do
      candidate="$node_bin/$name"
      if [ -f "$candidate" ] || [ -x "$candidate" ]; then
        to_cmd_path "$candidate"
        return
      fi
    done
  fi
  for name in npm.cmd npm; do
    candidate="$(command -v "$name" 2>/dev/null || true)"
    case "$candidate" in
      *node_modules/.bin/*) continue ;;
    esac
    if [ -n "$candidate" ]; then
      to_cmd_path "$candidate"
      return
    fi
  done
  for name in npm.cmd npm; do
    candidate="$(command -v "$name" 2>/dev/null || true)"
    if [ -n "$candidate" ]; then
      to_cmd_path "$candidate"
      return
    fi
  done
}

to_cmd_path() {
  path_value="$1"
  if [ -z "$path_value" ]; then
    return
  fi
  if have cygpath; then
    cygpath -w "$path_value" 2>/dev/null || printf '%s\n' "$path_value"
    return
  fi
  printf '%s\n' "$path_value"
}

package_spec_for_node() {
  package_spec="$1"
  if [ "$os" = msys ] && have cygpath && [ -e "$package_spec" ]; then
    cygpath -w "$package_spec" 2>/dev/null || printf '%s\n' "$package_spec"
    return
  fi
  printf '%s\n' "$package_spec"
}

run_installer_package() {
  if [ -n "$SELLABLE_INSTALL_NPM_COMMAND" ]; then
    NPM_CMD="$SELLABLE_INSTALL_NPM_COMMAND"
  elif have npm.cmd; then
    NPM_CMD="npm.cmd"
  else
    NPM_CMD="npm"
  fi
  log "running $SELLABLE_INSTALL_PACKAGE_SPEC"
  set -- --host "$SELLABLE_INSTALLER_HOST" --mcp-package "$SELLABLE_MCP_PACKAGE_SPEC"
  if [ -n "$SELLABLE_CONFIG_PATH" ]; then
    set -- "$@" --sellable-config-path "$SELLABLE_CONFIG_PATH"
  fi
  if [ -n "$SELLABLE_CONFIGS_DIR" ]; then
    set -- "$@" --sellable-configs-dir "$SELLABLE_CONFIGS_DIR"
  fi
  "$NPM_CMD" exec --yes --package "$SELLABLE_INSTALL_PACKAGE_SPEC" -- sellable "$@"
}

run_verify() {
  if [ "$SELLABLE_INSTALLER_SKIP_VERIFY" = 1 ]; then
    warn "skipping runtime verification because SELLABLE_INSTALLER_SKIP_VERIFY=1"
    return
  fi
  verify_artifact="$STATE_ROOT/.last-verify.json"
  if have sellable; then
    VERIFY_CMD="$(command -v sellable)"
  else
    VERIFY_CMD="$INSTALL_DIR/sellable"
  fi
  [ -x "$VERIFY_CMD" ] || die "sellable command was not found after install"
  log "verifying Sellable MCP tools and create-campaign bootstrap"
  set -- --verify-only --host "$SELLABLE_INSTALLER_HOST" --mcp-package "$SELLABLE_MCP_PACKAGE_SPEC"
  if [ -n "$SELLABLE_CONFIG_PATH" ]; then
    set -- "$@" --sellable-config-path "$SELLABLE_CONFIG_PATH"
  fi
  if [ -n "$SELLABLE_CONFIGS_DIR" ]; then
    set -- "$@" --sellable-configs-dir "$SELLABLE_CONFIGS_DIR"
  fi
  "$VERIFY_CMD" "$@" --json --artifact "$verify_artifact" >/dev/null
}

need_home_or_install_dir

if [ -z "$SELLABLE_INSTALL_PACKAGE_SPEC" ]; then
  SELLABLE_INSTALL_PACKAGE_SPEC="$DEFAULT_SELLABLE_INSTALL_PACKAGE_SPEC"
fi
if [ -z "$SELLABLE_MCP_PACKAGE_SPEC" ]; then
  SELLABLE_MCP_PACKAGE_SPEC="$DEFAULT_SELLABLE_MCP_PACKAGE_SPEC"
fi
if [ -z "$SELLABLE_INSTALLER_HOST" ]; then
  SELLABLE_INSTALLER_HOST="all"
fi
if [ -z "$SELLABLE_INSTALLER_SKIP_VERIFY" ]; then
  SELLABLE_INSTALLER_SKIP_VERIFY=0
fi
if [ -z "$SELLABLE_INSTALLER_SKIP_PATH_UPDATE" ]; then
  SELLABLE_INSTALLER_SKIP_PATH_UPDATE=0
fi
if [ -z "$SELLABLE_INSTALLER_MODE" ]; then
  SELLABLE_INSTALLER_MODE="curl-sh"
fi
if [ -z "$SELLABLE_INSTALLER_FORCE_UNSUPPORTED" ]; then
  SELLABLE_INSTALLER_FORCE_UNSUPPORTED=0
fi

if [ -z "$SELLABLE_INSTALL_DIR" ]; then
  INSTALL_DIR="$HOME/.local/bin"
else
  INSTALL_DIR="$SELLABLE_INSTALL_DIR"
fi

if [ -n "$XDG_STATE_HOME" ]; then
  STATE_ROOT="$XDG_STATE_HOME/sellable/app-sellable-dev/installer"
elif [ -n "$HOME" ]; then
  STATE_ROOT="$HOME/.local/sellable/app-sellable-dev/installer"
else
  STATE_ROOT="$TMPDIR/sellable/app-sellable-dev/installer"
fi

mkdir -p "$INSTALL_DIR" || die "could not create install dir $INSTALL_DIR. Set SELLABLE_INSTALL_DIR to a writable directory and rerun the installer."
mkdir -p "$STATE_ROOT" || die "could not create state root $STATE_ROOT. Set XDG_STATE_HOME to a writable directory or set HOME to a writable home directory and rerun the installer."

os="$(detect_os)"
arch="$(detect_arch)"
libc="$(detect_libc)"
NODE_CURRENT_DIR="$STATE_ROOT/node-current"

SELLABLE_INSTALL_PACKAGE_SPEC="$(package_spec_for_node "$SELLABLE_INSTALL_PACKAGE_SPEC")"
SELLABLE_MCP_PACKAGE_SPEC="$(package_spec_for_node "$SELLABLE_MCP_PACKAGE_SPEC")"
export SELLABLE_INSTALL_PACKAGE_SPEC
export SELLABLE_MCP_PACKAGE_SPEC

log "Sellable installer script v$SELLABLE_INSTALLER_SCRIPT_VERSION"
log "platform os=$os arch=$arch libc=$libc"
log "install dir: $INSTALL_DIR"
log "state root: $STATE_ROOT"
log "installer package: $SELLABLE_INSTALL_PACKAGE_SPEC"
log "mcp package: $SELLABLE_MCP_PACKAGE_SPEC"
print_proxy_state

if have_compatible_node_stack; then
  log "using system Node $(node -v)"
  write_state ".node-version" "$(node -v) system $(command -v node)"
else
  install_node_runtime "$os" "$arch" "$libc"
fi

if [ -z "$SELLABLE_INSTALL_NODE_BIN" ]; then
  SELLABLE_INSTALL_NODE_BIN="$(resolve_node_bin)"
fi
export SELLABLE_INSTALL_NODE_BIN
if [ -z "$SELLABLE_INSTALL_NPM_COMMAND" ]; then
  SELLABLE_INSTALL_NPM_COMMAND="$(resolve_npm_command "$SELLABLE_INSTALL_NODE_BIN")"
fi
if [ -n "$SELLABLE_INSTALL_NPM_COMMAND" ]; then
  export SELLABLE_INSTALL_NPM_COMMAND
  if [ -z "$SELLABLE_INSTALL_NPM_CMD_COMMAND" ]; then
    SELLABLE_INSTALL_NPM_CMD_COMMAND="$(resolve_npm_cmd_command "$SELLABLE_INSTALL_NODE_BIN")"
  fi
  export SELLABLE_INSTALL_NPM_CMD_COMMAND
fi
if [ -n "$SELLABLE_INSTALL_NODE_BIN" ]; then
  export PATH="$INSTALL_DIR:$SELLABLE_INSTALL_NODE_BIN:$PATH"
else
  export PATH="$INSTALL_DIR:$PATH"
fi
write_state ".install-method" "$SELLABLE_INSTALLER_MODE"
write_state ".installer-version" "$SELLABLE_INSTALLER_SCRIPT_VERSION $SELLABLE_INSTALL_PACKAGE_SPEC $SELLABLE_MCP_PACKAGE_SPEC"
update_path_profile
run_installer_package
run_verify

log "Sellable is installed and verified."
log "Restart Claude Code/Codex Desktop/Hermes, or run /reload-mcp and /reload-skills in Hermes, then start a fresh agent thread so MCP tools reload."
log "Run /sellable:create-campaign in Claude Code, \$sellable:create-campaign in Codex, or /sellable-create-campaign in Hermes."
log "Run /sellable:create-evergreen-campaigns in Claude Code, \$sellable:create-evergreen-campaigns in Codex, or /sellable-create-evergreen-campaigns in Hermes."
log "Run /sellable:refresh-sender-engagement in Claude Code, \$sellable:refresh-sender-engagement in Codex, or /sellable-refresh-sender-engagement in Hermes."
