#!/bin/sh
# claude-forget launcher: makes Claude Code forget folders on this computer.
#
#   curl -fsSL https://ccc.hajimi.download | sh
#   curl -fsSL https://ccc.hajimi.download | sh -s -- --dry-run ~/some/folder
#
# It downloads claude-forget into a temporary folder, checks its SHA-256, runs it,
# then deletes the temporary folder and removes this command from your shell
# history files. If no Python 3.10+ is installed, a standalone Python is fetched
# into the same temporary folder and deleted with it. Nothing is installed.
#
# The whole script is one function call, so a cut-off download runs nothing.

set -eu

BASE="https://ccc.hajimi.download"
VERSION="0.2.1"
PYZ_SHA256="3b0e245be9e64ebbf7b2384472b899dd556f8554debf1f7cabed799c480f2423"
HOST="ccc.hajimi.download"

PBS_RELEASE="20261026"
PBS_PYTHON="3.13.18"

say() { printf '%s\n' "$*" >&2; }
die() { say "claude-forget: $*"; exit 1; }

fetch() { # url destination
  if command -v curl >/dev/null 2>&1; then
    curl -fsSL --proto '=https' --tlsv1.2 -o "$2" "$1"
  elif command -v wget >/dev/null 2>&1; then
    wget -q --https-only -O "$2" "$1"
  else
    die "needs curl or wget"
  fi
}

sha256_of() {
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$1" | cut -d ' ' -f 1
  elif command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$1" | cut -d ' ' -f 1
  elif command -v openssl >/dev/null 2>&1; then
    openssl dgst -sha256 -r "$1" | cut -d ' ' -f 1
  else
    die "needs sha256sum, shasum or openssl to verify the download"
  fi
}

verify() { # file expected-sha256
  [ "$(sha256_of "$1")" = "$2" ] || die "checksum mismatch for $(basename "$1"); not running it"
}

# Prints the path of a usable Python 3.10+ interpreter, if one is installed.
find_python() {
  for candidate in python3 python3.14 python3.13 python3.12 python3.11 python3.10 python; do
    if command -v "$candidate" >/dev/null 2>&1 &&
      "$candidate" -c 'import sys; sys.exit(sys.version_info < (3, 10))' >/dev/null 2>&1; then
      command -v "$candidate"
      return 0
    fi
  done
  return 1
}

# Fetches python-build-standalone into $1 and prints its interpreter path.
standalone_python() {
  case "$(uname -s)-$(uname -m)" in
    Linux-x86_64 | Linux-amd64)
      triple="x86_64-unknown-linux-gnu"
      sum="df15fe60d3ff55bf9dcf25824b5572756bb8816ff93865a273d3301d7066a8b7" ;;
    Linux-aarch64 | Linux-arm64)
      triple="aarch64-unknown-linux-gnu"
      sum="578d9da1983463ffb0c8c98ab0da2f18177f44069328eb0af847860c1eb05c3e" ;;
    Darwin-x86_64)
      triple="x86_64-apple-darwin"
      sum="7412c19d896c99431b74a18a5643e110449a7f9590fbab179c3e5ab27b9aa9e3" ;;
    Darwin-arm64)
      triple="aarch64-apple-darwin"
      sum="8392b6ea51d94391befb2c31ebe75463f045d0b69dfcf5e1bb3234e1f5fa3405" ;;
    *) die "no Python 3.10+ found and no standalone build for $(uname -s) $(uname -m); install python3 and retry" ;;
  esac
  if [ "$(uname -s)" = Linux ] && ldd --version 2>&1 | grep -qi musl; then
    die "no Python 3.10+ found (musl systems need a distro python3, e.g. apk add python3)"
  fi
  say "No Python 3.10+ found; fetching a temporary Python $PBS_PYTHON (deleted afterwards)..."
  archive="$1/python.tar.gz"
  fetch "https://github.com/astral-sh/python-build-standalone/releases/download/$PBS_RELEASE/cpython-$PBS_PYTHON%2B$PBS_RELEASE-$triple-install_only_stripped.tar.gz" "$archive"
  verify "$archive" "$sum"
  tar -xzf "$archive" -C "$1"
  rm -f "$archive"
  printf '%s\n' "$1/python/bin/python3"
}

main() {
  tmp=$(mktemp -d 2>/dev/null || mktemp -d -t claude-forget) || die "cannot create a temporary folder"
  trap 'rm -rf "$tmp"' EXIT
  trap 'exit 130' INT
  trap 'exit 143' TERM
  trap 'exit 129' HUP

  fetch "$BASE/claude-forget-$VERSION.pyz" "$tmp/claude-forget.pyz"
  verify "$tmp/claude-forget.pyz" "$PYZ_SHA256"
  python=$(find_python) || python=$(standalone_python "$tmp")

  # This script arrives on stdin, so the program reads the keyboard from the terminal.
  status=0
  if (: </dev/tty) 2>/dev/null; then
    "$python" -I -B "$tmp/claude-forget.pyz" --scrub-shell-history "$HOST" "$@" </dev/tty || status=$?
  else
    "$python" -I -B "$tmp/claude-forget.pyz" --scrub-shell-history "$HOST" "$@" || status=$?
  fi
  return "$status"
}

main "$@"
