install.sh
Rama main · réplica de lectura del repositorio original.
#!/bin/sh
# CRW installer. Downloads the latest release binary for your platform.
# Usage:
# curl -fsSL https://fastcrw.com/install | sh
# wget -qO- https://fastcrw.com/install | sh
#
# Options (environment variables):
# CRW_VERSION=v0.3.0 Install a specific version instead of latest
# CRW_INSTALL_DIR=~/.local/bin Custom install directory
# CRW_BINARY=crw-mcp Install crw-mcp (MCP server) or crw-server instead of
# the default crw CLI
# CRW_API_KEY=crw_live_… Connect to CRW Cloud and register the MCP server
# with every detected AI coding tool, in one command
# CRW_NO_AGENTS=1 With CRW_API_KEY, skip the AI-tool registration
set -eu
main() {
REPO="fastcrw/crw"
INSTALL_DIR="${CRW_INSTALL_DIR:-/usr/local/bin}"
BINARY="${CRW_BINARY:-crw}"
# --- helpers ----------------------------------------------------------------
BOLD="$(tput bold 2>/dev/null || printf '')"
BLUE="$(tput setaf 4 2>/dev/null || printf '')"
GREEN="$(tput setaf 2 2>/dev/null || printf '')"
RED="$(tput setaf 1 2>/dev/null || printf '')"
RESET="$(tput sgr0 2>/dev/null || printf '')"
info() { printf '%s==>%s %s\n' "${BLUE}${BOLD}" "${RESET}" "$*"; }
success() { printf '%s==>%s %s\n' "${GREEN}${BOLD}" "${RESET}" "$*"; }
err() { printf '%serror:%s %s\n' "${RED}${BOLD}" "${RESET}" "$*" >&2; exit 1; }
need() {
command -v "$1" >/dev/null 2>&1 || err "'$1' is required but not found"
}
# Print a binary's version line, or nothing. Only the `crw` CLI has a --version
# flag; crw-mcp and crw-server reject it, so callers must treat an empty result
# as "unknown" and fall back to the plain binary name.
version_of() {
"$1" --version 2>/dev/null | head -1
}
# --- detect downloader ------------------------------------------------------
download() {
if command -v curl >/dev/null 2>&1; then
curl --fail --location --silent --show-error \
--proto '=https' --tlsv1.2 \
--output "$2" "$1"
elif command -v wget >/dev/null 2>&1; then
wget --https-only --quiet --output-document="$2" "$1"
else
err "curl or wget is required"
fi
}
# --- detect platform --------------------------------------------------------
detect_platform() {
OS="$(uname -s)"
ARCH="$(uname -m)"
case "$OS" in
Darwin) PLATFORM="darwin" ;;
Linux) PLATFORM="linux" ;;
MINGW*|MSYS*|CYGWIN*) PLATFORM="win32" ;;
*) err "Unsupported OS: $OS. Try: cargo install $BINARY" ;;
esac
# Rosetta 2 detection: uname returns x86_64 under Rosetta on Apple Silicon
if [ "$PLATFORM" = "darwin" ] && [ "$ARCH" = "x86_64" ]; then
if sysctl -n sysctl.proc_translated 2>/dev/null | grep -q '^1$'; then
info "Rosetta 2 detected, installing native arm64 binary"
ARCH="arm64"
fi
fi
case "$ARCH" in
x86_64|amd64) ARCH_LABEL="x64" ;;
aarch64|arm64) ARCH_LABEL="arm64" ;;
*) err "Unsupported architecture: $ARCH. Try: cargo install $BINARY" ;;
esac
# Linux binaries are static musl builds, so they run on ANY libc (glibc and
# musl/Alpine alike), so no libc gate is needed.
if [ "$PLATFORM" = "win32" ]; then
ASSET="${BINARY}-${PLATFORM}-${ARCH_LABEL}.zip"
else
ASSET="${BINARY}-${PLATFORM}-${ARCH_LABEL}.tar.gz"
fi
}
# --- pick the download URL ----------------------------------------------------
# Unpinned, we hand the download straight to GitHub's own
# `releases/latest/download/<asset>` redirect instead of first asking the REST
# API which tag is latest. That API allows 60 unauthenticated requests per hour
# per IP, so on any shared address (CI runners, an office NAT, a cloud VM) the
# tag lookup was what failed, never the download itself. The redirect is not
# rate limited and needs no token.
pick_url() {
if [ -n "${CRW_VERSION:-}" ]; then
VERSION="$CRW_VERSION"
URL="https://github.com/${REPO}/releases/download/${VERSION}/${ASSET}"
else
# Empty means "whatever the redirect gives us"; messages say "latest" and
# the real tag is read back off the binary once it is installed.
VERSION=""
URL="https://github.com/${REPO}/releases/latest/download/${ASSET}"
fi
}
# --- download & install -----------------------------------------------------
install() {
CRW_TMPDIR="$(mktemp -d)"
trap 'rm -rf "$CRW_TMPDIR"' EXIT
# Check for existing installation
if command -v "$BINARY" >/dev/null 2>&1; then
INSTALLED="$(version_of "$BINARY")"
info "Upgrading ${INSTALLED:-$BINARY} to ${VERSION:-latest}..."
else
info "Downloading ${BINARY} ${VERSION:-latest} (${PLATFORM}/${ARCH_LABEL})..."
fi
download "$URL" "${CRW_TMPDIR}/${ASSET}"
info "Extracting..."
if [ "$PLATFORM" = "win32" ]; then
need unzip
unzip -o "${CRW_TMPDIR}/${ASSET}" -d "$CRW_TMPDIR" >/dev/null
else
tar xzf "${CRW_TMPDIR}/${ASSET}" -C "$CRW_TMPDIR"
fi
# Verify the binary was extracted
[ -f "${CRW_TMPDIR}/${BINARY}" ] || err "Archive did not contain '${BINARY}'"
# Create install directory if needed
if [ ! -d "$INSTALL_DIR" ]; then
if [ -w "$(dirname "$INSTALL_DIR")" ]; then
mkdir -p "$INSTALL_DIR"
else
sudo mkdir -p "$INSTALL_DIR"
fi
fi
info "Installing to ${INSTALL_DIR}/${BINARY}..."
if [ -w "$INSTALL_DIR" ]; then
mv "${CRW_TMPDIR}/${BINARY}" "${INSTALL_DIR}/${BINARY}"
chmod +x "${INSTALL_DIR}/${BINARY}"
else
sudo mv "${CRW_TMPDIR}/${BINARY}" "${INSTALL_DIR}/${BINARY}"
sudo chmod +x "${INSTALL_DIR}/${BINARY}"
fi
# With the `latest` redirect the tag is never known up front, so report the
# version the installed binary actually is rather than the label we asked for.
INSTALLED_VERSION="$(version_of "${INSTALL_DIR}/${BINARY}")"
success "${INSTALLED_VERSION:-$BINARY} installed to ${INSTALL_DIR}/${BINARY}"
echo ""
# Check if install dir is in PATH
case ":$PATH:" in
*":${INSTALL_DIR}:"*) ;;
*) echo " Note: ${INSTALL_DIR} is not in your PATH. Add it with:"
echo " export PATH=\"${INSTALL_DIR}:\$PATH\""
echo "" ;;
esac
# First-run onboarding (crw CLI only). Basic local scraping needs no setup,
# so installation must never drop users into an unsolicited wizard. An API
# key supplied explicitly is still a deliberate one-command cloud connect;
# otherwise print the runnable first command and keep setup clearly optional.
if [ "$BINARY" = "crw" ]; then
if [ -n "${CRW_API_KEY:-}" ]; then
# One-command cloud connect: `curl … | CRW_API_KEY=crw_live_… sh`.
# Non-interactive: validates the key and writes config.toml, no /dev/tty
# needed (works in CI too).
echo ""
info "Connecting to CRW Cloud with your API key…"
echo ""
# Registration into detected AI tools is part of the same command; the
# pasted CRW_API_KEY is the consent a piped installer cannot prompt for.
# CRW_NO_AGENTS=1 opts out.
if [ -n "${CRW_NO_AGENTS:-}" ]; then
"${INSTALL_DIR}/${BINARY}" setup --api-key "${CRW_API_KEY}" --no-agents \
|| info "Cloud connect failed. Run 'crw setup --api-key <key>' to retry."
else
"${INSTALL_DIR}/${BINARY}" setup --api-key "${CRW_API_KEY}" \
|| info "Cloud connect failed. Run 'crw setup --api-key <key>' to retry."
fi
else
echo ""
echo " Run: crw https://example.com"
echo " Optional: crw setup # connect Cloud or add local JS/search"
echo " Help: crw --help"
echo ""
fi
else
echo ""
echo " Run: ${BINARY} --help"
echo ""
fi
}
# --- run --------------------------------------------------------------------
detect_platform
pick_url
install
}
# main() wrapper ensures the entire script is downloaded before execution
main