#!/usr/bin/env bash # 창진 에이전트(cjagent) 설치 스크립트 — Linux / macOS # curl -fsSL https://cjsoft.pe.kr/download/install.sh | bash # 다른 서버에서 호스팅 시: CJAGENT_DOWNLOAD_URL 환경변수로 오버라이드. # ※ CJAGENT_BASE_URL 은 쓰지 않는다 — cjagent 본체가 그 변수를 '모델 서버' 주소로 읽는다 # (cjagent/config.py). 모델 서버를 가리키도록 설정해 둔 PC 에서 설치를 돌리면 # 엉뚱한 호스트에서 wheel 을 받으려다 실패한다. set -euo pipefail BASE="${CJAGENT_DOWNLOAD_URL:-${CJAGENT_UPDATE_URL:-https://cjsoft.pe.kr}}" BASE="${BASE%/}" echo "" echo " 창진 에이전트(cjagent) 설치" echo " ---------------------------" # ── 1) Python 3.10+ 탐지 ── PY="" for c in python3 python; do if command -v "$c" >/dev/null 2>&1; then if "$c" -c 'import sys; sys.exit(0 if sys.version_info >= (3,10) else 1)' 2>/dev/null; then PY="$c"; break fi fi done if [ -z "$PY" ]; then echo " [오류] Python 3.10+ 가 필요합니다." >&2 echo " https://www.python.org/downloads/ (또는 패키지 매니저)로 설치 후 다시 실행하세요." >&2 exit 1 fi echo " Python : $("$PY" --version 2>&1)" # ── 2) 최신 버전 메타 ── WHEEL="" if command -v curl >/dev/null 2>&1; then META="$(curl -fsSL "$BASE/download/latest.json" 2>/dev/null || true)" elif command -v wget >/dev/null 2>&1; then META="$(wget -qO- "$BASE/download/latest.json" 2>/dev/null || true)" else META="" fi if [ -n "$META" ]; then W="$(printf '%s' "$META" | sed -n 's/.*"wheel"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)" [ -n "$W" ] && WHEEL="$W" fi if [ -z "$WHEEL" ]; then echo " [오류] 최신 버전 정보를 가져오지 못했습니다 — 네트워크 연결을 확인한 뒤 다시 시도하세요." >&2 exit 1 fi URL="$BASE/download/$WHEEL" echo " 패키지 : $WHEEL" # ── 3) 설치 (pipx 우선 → 전용 venv 폴백) ── # pip --user 는 최신 배포판(PEP 668 externally-managed)에서 실패하므로, pipx가 없으면 # 전용 가상환경을 만들고 ~/.local/bin 에 링크한다(어디서나 안전·격리). echo "" INSTALLED=0 if command -v pipx >/dev/null 2>&1; then echo " 방법 : pipx (격리 설치)" echo "" # pipx 가 깨져 있어도(구버전·손상된 shared venv) 설치를 포기하지 않고 venv 로 폴백한다. if pipx install --force "$URL"; then INSTALLED=1 else echo "" echo " pipx 설치 실패 — 전용 가상환경 방식으로 다시 시도합니다." >&2 fi fi if [ "$INSTALLED" -eq 0 ]; then echo " 방법 : 전용 가상환경 (PEP 668 안전)" echo "" VENV="${XDG_DATA_HOME:-$HOME/.local/share}/cjagent/venv" BIN="$HOME/.local/bin" # 재설치 안전: 쓸 수 있는 환경이면 그대로 재사용하고, 못 쓰는 잔해만 --clear 로 정리한다. VENV_ARGS=(--clear) if [ -f "$VENV/pyvenv.cfg" ] && "$VENV/bin/python" -c \ 'import sys; sys.exit(0 if sys.version_info >= (3,10) else 1)' 2>/dev/null; then VENV_ARGS=(--upgrade) echo " 기존 환경을 재사용합니다: $VENV" fi if "$PY" -m venv "${VENV_ARGS[@]}" "$VENV"; then "$VENV/bin/python" -m pip install --upgrade -q pip >/dev/null 2>&1 || true # 설치 → import 확인 → 깨졌으면 의존성까지 강제 재설치. # pip 가 "성공"으로 끝나도 못 쓰는 환경이 나올 수 있다(반쪽만 남은 패키지의 # dist-info 가 멀쩡하면 pip 는 "이미 설치됨"으로 건너뛴다). import 로 확인해야 잡힌다. CHK='import importlib,sys bad=[] for m in ("certifi","requests","yaml","rich","cjagent"): try: importlib.import_module(m) except Exception as e: bad.append(m+": "+type(e).__name__+": "+str(e)[:120]) sys.stdout.write("\n".join(bad))' "$VENV/bin/python" -m pip install --upgrade "$URL" BAD="$("$VENV/bin/python" -c "$CHK" 2>&1)" if [ -n "$BAD" ]; then echo "" >&2 echo " 설치 후 확인에서 문제가 발견됐습니다:" >&2 echo "$BAD" | sed 's/^/ /' >&2 echo " 의존성까지 다시 설치해 복구를 시도합니다…" >&2 "$VENV/bin/python" -m pip install --upgrade --force-reinstall "$URL" BAD="$("$VENV/bin/python" -c "$CHK" 2>&1)" if [ -n "$BAD" ]; then echo "" >&2 echo " [오류] 복구하지 못했습니다:" >&2 echo "$BAD" | sed 's/^/ /' >&2 echo " 환경을 새로 만든 뒤 다시 시도해 주세요: rm -rf \"$VENV\"" >&2 exit 1 fi fi mkdir -p "$BIN" ln -sf "$VENV/bin/cjagent" "$BIN/cjagent" echo " 설치 위치: $VENV" echo " 실행 파일: $BIN/cjagent" else echo " [오류] 가상환경 생성 실패 — python3-venv(또는 pipx)가 필요할 수 있습니다:" >&2 echo " Debian/Ubuntu: sudo apt install -y python3-venv pipx" >&2 echo " macOS(Homebrew): brew install pipx" >&2 exit 1 fi fi echo "" echo " 설치 완료!" echo " 다음을 실행해 보세요:" echo " cjagent doctor # 환경 진단(모델 서버·PATH 확인)" echo " cjagent web # 웹 UI 실행" echo "" echo " * 'cjagent' 명령을 못 찾으면 ~/.local/bin 이 PATH에 있는지 확인하세요:" echo " export PATH=\"\$HOME/.local/bin:\$PATH\""