Загрузить файлы в «/»

This commit is contained in:
2026-07-15 13:15:52 +00:00
parent c5c7a0344e
commit 1a544e4684
5 changed files with 1261 additions and 0 deletions
+409
View File
@@ -0,0 +1,409 @@
#!/usr/bin/env bash
# installagent — install CLI AI coding agents inside asandbox
# Usage: installagent <name> | installagent list | installagent status
set -euo pipefail
VERSION="1.1.0"
if [[ -t 2 ]]; then
C_RED=$'\033[31m'; C_GRN=$'\033[32m'; C_YLW=$'\033[33m'
C_BLU=$'\033[34m'; C_DIM=$'\033[2m'; C_RST=$'\033[0m'; C_BLD=$'\033[1m'
else
C_RED=; C_GRN=; C_YLW=; C_BLU=; C_DIM=; C_RST=; C_BLD=
fi
die() { echo "${C_RED}installagent:${C_RST} $*" >&2; exit 1; }
info() { echo "${C_BLU}installagent:${C_RST} $*" >&2; }
ok() { echo "${C_GRN}installagent:${C_RST} $*" >&2; }
warn() { echo "${C_YLW}installagent:${C_RST} $*" >&2; }
ensure_local_path() {
mkdir -p "${HOME}/.local/bin" "${HOME}/.local/lib" "${HOME}/.npm-global"
# Prefer user-local npm so installs survive container recreate (via persist mount)
if command -v npm >/dev/null 2>&1; then
npm config set prefix "${HOME}/.npm-global" >/dev/null 2>&1 || true
fi
export PATH="${HOME}/.local/bin:${HOME}/.npm-global/bin:${PATH}"
}
npm_g() {
ensure_local_path
npm install -g --prefix "${HOME}/.npm-global" "$@"
}
have_cmd() { command -v "$1" >/dev/null 2>&1; }
# ── catalog ─────────────────────────────────────────────────────────
# id|aliases|binary|description
catalog() {
cat <<'EOF'
antigravity|agy,antigravity-cli|agy|Google Antigravity CLI
cursor|cursor-cli,cursor-agent|agent|Cursor Agent CLI
opencode|open-code|opencode|OpenCode open-source coding agent
claude|claude-code,claude-cli|claude|Anthropic Claude Code
gemini|gemini-cli,google-gemini|gemini|Google Gemini CLI
codex|openai-codex|codex|OpenAI Codex CLI
aider|aider-chat|aider|Aider Python coding agent
qwen|qwen-code,qwen-cli|qwen|Qwen Code CLI
amp|sourcegraph-amp|amp|Sourcegraph Amp CLI
goose|block-goose|goose|Block Goose agent
continue|cn|cn|Continue CLI
EOF
}
normalize_name() {
echo "$1" | tr '[:upper:]' '[:lower:]' | tr '_' '-'
}
resolve_id() {
local want
want=$(normalize_name "$1")
local line id aliases
while IFS= read -r line; do
[[ -z "$line" || "$line" == \#* ]] && continue
id="${line%%|*}"
aliases="${line#*|}"
aliases="${aliases%%|*}"
if [[ "$want" == "$id" ]]; then
echo "$id"
return 0
fi
local a
IFS=',' read -ra _als <<< "$aliases"
for a in "${_als[@]}"; do
a=$(echo "$a" | tr -d ' ')
if [[ "$want" == "$a" ]]; then
echo "$id"
return 0
fi
done
done < <(catalog)
return 1
}
agent_binary() {
local id="$1" line
while IFS= read -r line; do
[[ "${line%%|*}" == "$id" ]] || continue
# id|aliases|binary|desc
local rest="${line#*|}"
rest="${rest#*|}"
echo "${rest%%|*}"
return 0
done < <(catalog)
}
agent_desc() {
local id="$1" line
while IFS= read -r line; do
[[ "${line%%|*}" == "$id" ]] || continue
echo "${line##*|}"
return 0
done < <(catalog)
}
# ── installers ──────────────────────────────────────────────────────
install_antigravity() {
info "installing Antigravity CLI (agy)..."
ensure_local_path
curl -fsSL https://antigravity.google/cli/install.sh | bash
# Some installers put binary only in a custom dir — ensure on PATH
if ! have_cmd agy; then
# common locations
for p in \
"${HOME}/.local/bin/agy" \
"${HOME}/.antigravity/bin/agy" \
"${HOME}/.agy/bin/agy" \
/usr/local/bin/agy; do
if [[ -x "$p" ]]; then
mkdir -p "${HOME}/.local/bin"
ln -sfn "$p" "${HOME}/.local/bin/agy"
break
fi
done
fi
have_cmd agy || die "agy not found after install — check installer output"
ok "Antigravity CLI ready: $(command -v agy)"
agy --version 2>/dev/null || agy version 2>/dev/null || true
}
install_cursor() {
info "installing Cursor Agent CLI..."
ensure_local_path
curl -fsSL https://cursor.com/install | bash
if ! have_cmd agent; then
for p in \
"${HOME}/.local/bin/agent" \
"${HOME}/.cursor/bin/agent" \
"${HOME}/.cursor-agent/bin/agent"; do
if [[ -x "$p" ]]; then
mkdir -p "${HOME}/.local/bin"
ln -sfn "$p" "${HOME}/.local/bin/agent"
break
fi
done
fi
have_cmd agent || die "agent not found after install"
ok "Cursor CLI ready: $(command -v agent)"
agent --version 2>/dev/null || true
}
install_opencode() {
info "installing OpenCode..."
ensure_local_path
if have_cmd npm; then
npm_g opencode-ai
else
curl -fsSL https://opencode.ai/install | bash
fi
if ! have_cmd opencode; then
for p in "${HOME}/.npm-global/bin/opencode" "${HOME}/.local/bin/opencode" /usr/local/bin/opencode; do
[[ -x "$p" ]] && ln -sfn "$p" "${HOME}/.local/bin/opencode" && break
done
fi
have_cmd opencode || die "opencode not found after install"
ok "OpenCode ready: $(command -v opencode)"
opencode --version 2>/dev/null || true
}
install_claude() {
info "installing Claude Code..."
have_cmd npm || die "npm required (Node.js)"
npm_g @anthropic-ai/claude-code
have_cmd claude || die "claude not found after install"
ok "Claude Code ready: $(command -v claude)"
claude --version 2>/dev/null || true
}
install_gemini() {
info "installing Gemini CLI..."
have_cmd npm || die "npm required (Node.js)"
npm_g @google/gemini-cli
have_cmd gemini || die "gemini not found after install"
ok "Gemini CLI ready: $(command -v gemini)"
gemini --version 2>/dev/null || true
}
install_codex() {
info "installing OpenAI Codex CLI..."
have_cmd npm || die "npm required (Node.js)"
npm_g @openai/codex
have_cmd codex || die "codex not found after install"
ok "Codex ready: $(command -v codex)"
codex --version 2>/dev/null || true
}
install_aider() {
info "installing Aider..."
ensure_local_path
if have_cmd uv; then
uv tool install aider-chat
elif have_cmd pip3; then
pip3 install --user --break-system-packages aider-chat \
|| pip3 install --user aider-chat
else
die "need uv or pip3 to install aider"
fi
# uv tools go to ~/.local/bin
have_cmd aider || die "aider not found after install — ensure ~/.local/bin is on PATH"
ok "Aider ready: $(command -v aider)"
aider --version 2>/dev/null || true
}
install_qwen() {
info "installing Qwen Code..."
have_cmd npm || die "npm required (Node.js)"
npm_g @qwen-code/qwen-code
# binary name may be qwen or qwen-code
if ! have_cmd qwen && have_cmd qwen-code; then
ln -sfn "$(command -v qwen-code)" "${HOME}/.local/bin/qwen"
fi
if have_cmd qwen || have_cmd qwen-code; then
ok "Qwen Code ready: $(command -v qwen 2>/dev/null || command -v qwen-code)"
else
die "qwen binary not found after install"
fi
}
install_amp() {
info "installing Amp (Sourcegraph)..."
ensure_local_path
# Official installer when available
if curl -fsSL https://ampcode.com/install.sh 2>/dev/null | bash; then
:
elif have_cmd npm; then
npm_g @sourcegraph/amp 2>/dev/null || npm_g amp 2>/dev/null || true
fi
have_cmd amp || warn "amp may need manual install — see https://ampcode.com"
have_cmd amp && ok "Amp ready: $(command -v amp)"
}
install_goose() {
info "installing Goose..."
ensure_local_path
curl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh 2>/dev/null | bash \
|| curl -fsSL https://raw.githubusercontent.com/block/goose/main/download_cli.sh 2>/dev/null | bash \
|| true
if ! have_cmd goose; then
# fallback cargo if present
if have_cmd cargo; then
cargo install goose-cli 2>/dev/null || true
fi
fi
have_cmd goose || die "goose not found after install — see https://github.com/block/goose"
ok "Goose ready: $(command -v goose)"
}
install_continue() {
info "installing Continue CLI..."
ensure_local_path
have_cmd npm || die "npm required"
npm_g @continuedev/cli 2>/dev/null || npm_g continue-cli 2>/dev/null || true
if have_cmd cn || have_cmd continue; then
ok "Continue ready: $(command -v cn 2>/dev/null || command -v continue)"
else
warn "Continue CLI package name may have changed — try: npm install -g @continuedev/cli"
fi
}
do_install() {
local id="$1"
case "$id" in
antigravity) install_antigravity ;;
cursor) install_cursor ;;
opencode) install_opencode ;;
claude) install_claude ;;
gemini) install_gemini ;;
codex) install_codex ;;
aider) install_aider ;;
qwen) install_qwen ;;
amp) install_amp ;;
goose) install_goose ;;
continue) install_continue ;;
*) die "no installer for: $id" ;;
esac
}
cmd_list() {
echo "${C_BLD}Available agents${C_RST} (installagent <name>)"
echo
printf " ${C_BLD}%-14s${C_RST} %-12s %s\n" "NAME" "BINARY" "DESCRIPTION"
printf " %-14s %-12s %s\n" "----" "------" "-----------"
local line id aliases bin desc
while IFS= read -r line; do
id="${line%%|*}"
rest="${line#*|}"
aliases="${rest%%|*}"
rest="${rest#*|}"
bin="${rest%%|*}"
desc="${rest#*|}"
local mark=" "
if have_cmd "$bin"; then
mark="${C_GRN}✓${C_RST}"
else
mark="${C_DIM}·${C_RST}"
fi
printf " %s %-12s %-12s %s\n" "$mark" "$id" "$bin" "$desc"
if [[ -n "$aliases" ]]; then
printf " ${C_DIM}aliases: %s${C_RST}\n" "$aliases"
fi
done < <(catalog)
echo
echo "Examples:"
echo " installagent claude"
echo " installagent antigravity"
echo " installagent cursor"
echo " installagent opencode"
echo " installagent all # install core set"
}
cmd_status() {
ensure_local_path
echo "${C_BLD}Installed agents${C_RST}"
local line id bin
while IFS= read -r line; do
id="${line%%|*}"
rest="${line#*|}"
rest="${rest#*|}"
bin="${rest%%|*}"
if have_cmd "$bin"; then
printf " ${C_GRN}✓${C_RST} %-14s %s\n" "$id" "$(command -v "$bin")"
else
printf " ${C_DIM}·${C_RST} %-14s (not installed)\n" "$id"
fi
done < <(catalog)
echo
echo "PATH includes:"
echo " ${HOME}/.local/bin"
echo " ${HOME}/.npm-global/bin"
}
cmd_all() {
# Core set commonly used
local core=(claude gemini codex opencode cursor antigravity aider)
local name
for name in "${core[@]}"; do
info "── $name ──"
if do_install "$name"; then
ok "$name done"
else
warn "$name failed (continuing)"
fi
done
cmd_status
}
usage() {
cat <<EOF
installagent v${VERSION} — install CLI AI agents inside asandbox
USAGE
installagent <name> Install agent by name or alias
installagent list Show catalog
installagent status Show what is installed
installagent all Install core agents
installagent help This help
AGENTS
antigravity (agy) Google Antigravity CLI
cursor (agent) Cursor Agent CLI
opencode OpenCode
claude Claude Code
gemini Gemini CLI
codex OpenAI Codex
aider Aider
qwen Qwen Code
amp Sourcegraph Amp
goose Block Goose
continue Continue CLI
Installs go to ~/.local and ~/.npm-global (persisted by asandbox).
EOF
}
main() {
ensure_local_path
local cmd="${1:-list}"
shift || true
case "$cmd" in
list|ls|-l) cmd_list ;;
status|st) cmd_status ;;
all) cmd_all ;;
help|-h|--help) usage ;;
version|-V|--version) echo "installagent $VERSION" ;;
*)
local id
if ! id=$(resolve_id "$cmd"); then
die "unknown agent: $cmd (try: installagent list)"
fi
info "resolved '$cmd' → $id ($(agent_desc "$id"))"
do_install "$id"
echo
ok "run: $(agent_binary "$id")"
;;
esac
}
main "$@"