Zuletzt aktiv 3 weeks ago

Interactive developer environment bootstrapper for Zsh/Bash with repeatable workstation setup helpers.

Änderung e91c26ac2f03c0996fe79043bd5711ecff087f6d

README.md Originalformat

Strict Developer Environment Installer

A robust, idempotent, and interactive bash script to bootstrap your macOS, Linux, or WSL development environment.

Unlike standard setup scripts that rely heavily on package managers like Homebrew or Apt (which can introduce bloat, dependency hell, or outdated packages), this script is designed with a "Strict Official Source" philosophy. It dynamically fetches the absolute latest binaries and pre-compiled releases directly from the official maintainers (e.g., GitHub API, Python.org, Amazon).

✨ Key Features

  • Zero-Brew Dependency: By default, it bypasses Homebrew entirely, fetching tools directly from official APIs and release pages (Homebrew is available as an optional install).
  • Idempotent: Safe to run multiple times. It intelligently checks if a tool is already installed before attempting to download it.
  • Dynamic Versioning: Pings official APIs (like GitHub Releases or go.dev/VERSION) to ensure you are downloading the exact latest version at the time of execution.
  • Auto-Path Management: Intelligently injects paths into a dedicated ~/.pathrc (or your .bashrc/.zshrc) without mangling your config files.
  • Architecture Aware: Automatically detects if you are running on Intel (x86_64) or Apple Silicon/ARM (aarch64/arm64) and downloads the correct binaries.

🚀 Usage

You can launch the interactive installer directly from your terminal with a single command:

bash -c "$(curl -fsSL https://opengist.rmrf.online/weehong/af1c64c143a44ffbb0a1632dd6a32af1/raw/HEAD/menu.sh)"

Once the menu loads, simply follow the interactive prompts. You can select multiple tools at once by entering space-separated numbers (e.g., 1 3 8 12).

🛠️ Included Tools

Core Runtimes & Managers

  • Build Tools: GCC, Make, Git, Curl, Unzip, and core libraries.
  • Homebrew: (Optional) Installed officially.
  • NVM (Node Version Manager): Includes interactive prompt to install LTS or Latest Node.js immediately.
  • Python 3: Fetches the latest stable .pkg for Mac or compiles strictly from source for Linux.
  • Go: Fetches the latest tarball and installs system-wide to /usr/local/go.
  • SDKMAN: For managing Java, Kotlin, and Gradle.
  • .NET: Installed via Microsoft's official script.

Cloud & Infrastructure

  • Docker: Downloads the official .dmg (macOS) or runs the official get.docker.com script (Linux) with auto-group assignment.
  • AWS CLI: Fetches the official binaries directly from Amazon.
  • Google Cloud CLI (gcloud): Official Google setup script.
  • Firebase CLI: Standalone binary (no Node.js required natively).

Dev Tools & Security

  • GitHub CLI (gh): Downloaded directly from GitHub Releases to /usr/local/bin.
  • Infisical CLI: Downloaded directly from GitHub Releases for secret management.

AI & Agentic Tools

  • Claude Code CLI: Anthropic's official agent.
  • OpenCode: AI agent orchestration.
  • OpenAI Codex CLI: Required NVM/Node.js to run.

⚠️ Important Notes & Troubleshooting

  • Restart Your Shell: After running the script for the first time, you should restart your terminal or run source ~/.bashrc (or ~/.zshrc) to ensure all new PATH variables (like NVM, Go, or .NET) take effect.
  • Docker Permissions (Linux): The script automatically adds your user to the docker group. You will need to log out and log back in for this to take effect.
  • AWS CLI on Linux: Ensure you install Build Tools (Option 1) first if you are on a fresh Linux install, as the AWS installer requires unzip to extract the payload.

Built for developers who want total control over their toolchain.

menu.sh Originalformat
1#!/usr/bin/env bash
2
3# =======================================================
4# 1. BOOTSTRAPPER: PREFER ZSH, FALLBACK TO BASH
5# =======================================================
6if [ -z "${_PREFER_ZSH_BOOTSTRAPPED:-}" ]; then
7 export _PREFER_ZSH_BOOTSTRAPPED=1
8
9 # Only attempt to re-execute if $0 is an actual file on disk.
10 # This prevents the 'can't open input file' error when running
11 # from memory via `bash -c "$(curl ...)"` or `zsh -c`.
12 if [ -f "$0" ]; then
13 if command -v zsh >/dev/null 2>&1; then
14 exec zsh "$0" "$@"
15 elif command -v bash >/dev/null 2>&1; then
16 exec bash "$0" "$@"
17 else
18 echo "Error: Neither Zsh nor Bash is installed. Exiting."
19 exit 1
20 fi
21 fi
22fi
23
24set -u
25
26# =======================================================
27# 2. CROSS-SHELL NORMALIZATION
28# =======================================================
29if [ -n "${ZSH_VERSION:-}" ]; then
30 # Zsh: Enable Bash-like word splitting for unquoted variables (menu input)
31 setopt shwordsplit 2>/dev/null || true
32 CURRENT_SHELL="zsh"
33 PROFILE_FILE="$HOME/.zshrc"
34elif [ -n "${BASH_VERSION:-}" ]; then
35 # Bash
36 CURRENT_SHELL="bash"
37 PROFILE_FILE="$HOME/.bashrc"
38else
39 # Fallback POSIX
40 CURRENT_SHELL="sh"
41 PROFILE_FILE="$HOME/.profile"
42fi
43
44# =======================================================
45# COLORS & LOGGING
46# =======================================================
47GREEN="\033[0;32m"
48RED="\033[0;31m"
49YELLOW="\033[1;33m"
50BLUE="\033[0;34m"
51NC="\033[0m"
52
53log() { printf "${GREEN}▶ %s${NC}\n" "$*"; }
54warn() { printf "${YELLOW}⚠ %s${NC}\n" "$*"; }
55err() { printf "${RED}✖ %s${NC}\n" "$*"; }
56info() { printf "${BLUE}ℹ %s${NC}\n" "$*"; }
57
58# =======================================================
59# HELPERS & SYSTEM DETECTION
60# =======================================================
61require_cmd() { command -v "$1" >/dev/null 2>&1; }
62
63add_to_path_config() {
64 local label=$1
65 local path_line=$2
66 local target_file="${3:-$PROFILE_FILE}"
67
68 if [[ -f "$target_file" ]]; then
69 if ! grep -q "$label" "$target_file"; then
70 printf "\n# %s\n%s\n" "$label" "$path_line" >> "$target_file"
71 log "Added $label to $target_file"
72 fi
73 else
74 printf "\n# %s\n%s\n" "$label" "$path_line" >> "$PROFILE_FILE"
75 log "Added $label to shell profile ($PROFILE_FILE)."
76 fi
77
78 # Instantly evaluate the path line so the current script session
79 # can immediately use the newly installed tool in subsequent steps.
80 eval "$path_line" 2>/dev/null || true
81}
82
83detect_os_arch() {
84 ARCH=$(uname -m)
85 case "$ARCH" in
86 x86_64|amd64) SYS_ARCH="amd64"; MAC_ARCH="x86_64"; AWS_ARCH="x86_64" ;;
87 aarch64|arm64) SYS_ARCH="arm64"; MAC_ARCH="arm64"; AWS_ARCH="aarch64" ;;
88 *) err "Unsupported architecture: $ARCH"; exit 1 ;;
89 esac
90
91 if [[ "$OSTYPE" == "darwin"* ]]; then
92 OS="macOS"
93 OS_LOWER="darwin"
94 elif grep -qi microsoft /proc/version 2>/dev/null; then
95 OS="WSL"
96 OS_LOWER="linux"
97 elif [[ -f /etc/os-release ]]; then
98 . /etc/os-release
99 [[ "$ID" == "ubuntu" || "$ID_LIKE" == *"ubuntu"* ]] && OS="Ubuntu" || OS="Linux"
100 OS_LOWER="linux"
101 else
102 OS="Unknown"
103 OS_LOWER="unknown"
104 fi
105 log "Detected: $OS ($ARCH) running $CURRENT_SHELL"
106}
107
108detect_os_arch
109
110# =======================================================
111# CORE RUNTIMES & MANAGERS
112# =======================================================
113
114install_build_tools() {
115 log "Installing Build Essentials & Core Dependencies..."
116 case "$OS" in
117 Ubuntu|WSL) sudo apt-get update && sudo apt-get install -y build-essential curl wget git jq unzip libssl-dev zlib1g-dev libffi-dev libsqlite3-dev ;;
118 macOS) xcode-select --install || warn "Xcode tools already installed" ;;
119 *) warn "Manual installation required for $OS." ;;
120 esac
121}
122
123install_brew() {
124 if require_cmd brew; then warn "Homebrew already installed"; return; fi
125 log "Installing Homebrew from Official Source..."
126
127 # Homebrew's installer specifically requires Bash execution, regardless of current shell
128 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
129
130 if [[ "$OS_LOWER" == "linux" ]]; then
131 add_to_path_config "HOMEBREW" 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"'
132 elif [[ "$MAC_ARCH" == "arm64" ]]; then
133 add_to_path_config "HOMEBREW" 'eval "$(/opt/homebrew/bin/brew shellenv)"'
134 else
135 add_to_path_config "HOMEBREW" 'eval "$(/usr/local/bin/brew shellenv)"'
136 fi
137}
138
139install_nvm() {
140 export NVM_DIR="$HOME/.nvm"
141
142 if [ -d "$NVM_DIR" ]; then
143 warn "NVM is already installed."
144 else
145 log "Installing NVM via $CURRENT_SHELL..."
146 curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | $CURRENT_SHELL
147 fi
148
149 [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
150
151 printf "\n${YELLOW}Which version of Node.js would you like to install?${NC}\n"
152 printf " 1) LTS (Long Term Support - Recommended for stability)\n"
153 printf " 2) Latest (Current features - Recommended for testing new APIs)\n"
154 printf " 3) Skip installing Node.js right now\n"
155
156 printf "Select (1/2/3): "
157 read node_choice
158
159 case "$node_choice" in
160 2)
161 log "Installing Latest Node.js..."
162 nvm install node
163 nvm alias default node
164 nvm use node
165
166 log "Disabling npm logs..."
167 npm config set logs-max 0
168 ;;
169 3)
170 log "Skipping Node.js installation."
171 ;;
172 *)
173 log "Installing Latest LTS Node.js..."
174 nvm install --lts
175 nvm alias default 'lts/*'
176 nvm use --lts
177
178 log "Disabling npm logs..."
179 npm config set logs-max 0
180 ;;
181 esac
182}
183
184install_python() {
185 log "Fetching latest stable Python version..."
186
187 LATEST_PY=$(curl -s https://www.python.org/downloads/ | grep -o 'Download Python 3\.[0-9]\{1,2\}\.[0-9]\{1,2\}' | head -1 | grep -o '3\.[0-9]\{1,2\}\.[0-9]\{1,2\}')
188 [[ -z "$LATEST_PY" ]] && LATEST_PY="3.12.3"
189
190 log "Detected Stable Version: $LATEST_PY"
191
192 if [[ "$OS" == "macOS" ]]; then
193 log "Downloading official macOS package..."
194 PKG_URL="https://www.python.org/ftp/python/${LATEST_PY}/python-${LATEST_PY}-macos11.pkg"
195 curl -fsSL -o /tmp/python.pkg "$PKG_URL"
196
197 log "Running installer..."
198 sudo installer -pkg /tmp/python.pkg -target /
199 rm /tmp/python.pkg
200 else
201 log "Installing build dependencies (zlib, ssl, etc)..."
202 sudo apt-get update && sudo apt-get install -y build-essential zlib1g-dev libssl-dev libffi-dev libsqlite3-dev
203
204 SRC_URL="https://www.python.org/ftp/python/${LATEST_PY}/Python-${LATEST_PY}.tgz"
205
206 log "Downloading $SRC_URL..."
207 curl -fSL -o /tmp/Python.tgz "$SRC_URL" || err "Failed to download Python source from $SRC_URL"
208
209 cd /tmp && tar -xzf Python.tgz && cd "Python-${LATEST_PY}"
210
211 log "Configuring build (with ensurepip)..."
212 ./configure --enable-optimizations --with-ensurepip=install
213
214 log "Compiling Python (this may take a few minutes)..."
215 sudo make altinstall
216
217 PY_MINOR=$(echo "$LATEST_PY" | cut -d. -f1,2)
218
219 log "Setting up symlinks..."
220 sudo ln -sf /usr/local/bin/python${PY_MINOR} /usr/local/bin/python3
221
222 if [[ -f "/usr/local/bin/pip${PY_MINOR}" ]]; then
223 sudo ln -sf /usr/local/bin/pip${PY_MINOR} /usr/local/bin/pip3
224 log "Successfully linked pip3!"
225 else
226 err "pip${PY_MINOR} was not generated during the build!"
227 fi
228
229 cd ~ && sudo rm -rf /tmp/Python*
230 fi
231
232 log "Python $LATEST_PY installation sequence finished!"
233}
234
235install_go() {
236 log "Fetching latest Go version from official source..."
237 LATEST_GO=$(curl -sL https://go.dev/VERSION?m=text | head -n 1)
238 TAR_FILE="${LATEST_GO}.${OS_LOWER}-${SYS_ARCH}.tar.gz"
239
240 log "Downloading $TAR_FILE..."
241 curl -fsSL -o /tmp/go.tar.gz "https://go.dev/dl/$TAR_FILE"
242
243 log "Installing to /usr/local/go..."
244 sudo rm -rf /usr/local/go
245 sudo tar -C /usr/local -xzf /tmp/go.tar.gz
246 rm /tmp/go.tar.gz
247 add_to_path_config "GO_BIN" 'export PATH="$PATH:/usr/local/go/bin"'
248}
249
250install_sdkman() {
251 if [ -d "$HOME/.sdkman" ]; then warn "SDKMAN already exists"; return; fi
252
253 # SDKMAN explicitly blocks macOS's default Bash 3.2.
254 # If we are trapped in Bash < 4, force the installer to use Zsh.
255 if [[ "$CURRENT_SHELL" == "bash" && "${BASH_VERSINFO[0]:-0}" -lt 4 ]]; then
256 log "Outdated Bash detected. Installing SDKMAN via Zsh..."
257 curl -s "https://get.sdkman.io" | zsh
258 else
259 log "Installing SDKMAN via $CURRENT_SHELL..."
260 curl -s "https://get.sdkman.io" | $CURRENT_SHELL
261 fi
262}
263
264install_dotnet() {
265 log "Installing .NET from official script..."
266 curl -fsSL https://dot.net/v1/dotnet-install.sh | $CURRENT_SHELL
267 add_to_path_config "DOTNET_TOOLS" 'export PATH="$PATH:$HOME/.dotnet/tools"'
268}
269
270install_android() {
271 log "Installing Android SDK command-line tools..."
272
273 if ! require_cmd unzip; then
274 err "unzip is required. Please install 'Build Tools' (Option 1) first."
275 return 1
276 fi
277
278 if [[ "$OS_LOWER" == "linux" && "$SYS_ARCH" != "amd64" ]]; then
279 err "Google's Android command-line tools installer supports Linux x86_64 only."
280 return 1
281 fi
282
283 ANDROID_HOME="$HOME/Android/Sdk"
284 ANDROID_SDK_ROOT="$ANDROID_HOME"
285 export ANDROID_HOME ANDROID_SDK_ROOT
286
287 mkdir -p "$ANDROID_HOME/cmdline-tools"
288
289 if [[ "$OS" == "macOS" ]]; then
290 TOOLS_OS="mac"
291 elif [[ "$OS_LOWER" == "linux" ]]; then
292 TOOLS_OS="linux"
293 else
294 err "Android SDK installation is not supported for $OS."
295 return 1
296 fi
297
298 log "Finding latest Android command-line tools from Google..."
299 TOOLS_URL=$(curl -fsSL https://developer.android.com/studio \
300 | grep -o "https://dl.google.com/android/repository/commandlinetools-${TOOLS_OS}-[0-9]*_latest.zip" \
301 | head -1)
302
303 if [[ -z "$TOOLS_URL" ]]; then
304 err "Could not find the Android command-line tools download URL."
305 return 1
306 fi
307
308 log "Downloading Android command-line tools..."
309 rm -rf /tmp/android-cmdline-tools /tmp/android-cmdline-tools.zip
310 mkdir -p /tmp/android-cmdline-tools
311 curl -fsSL -o /tmp/android-cmdline-tools.zip "$TOOLS_URL"
312 unzip -q /tmp/android-cmdline-tools.zip -d /tmp/android-cmdline-tools
313
314 rm -rf "$ANDROID_HOME/cmdline-tools/latest"
315 mkdir -p "$ANDROID_HOME/cmdline-tools/latest"
316 mv /tmp/android-cmdline-tools/cmdline-tools/* "$ANDROID_HOME/cmdline-tools/latest/"
317 rm -rf /tmp/android-cmdline-tools /tmp/android-cmdline-tools.zip
318
319 SDKMANAGER="$ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager"
320 if [[ ! -x "$SDKMANAGER" ]]; then
321 err "sdkmanager was not installed correctly."
322 return 1
323 fi
324
325 log "Accepting Android SDK licenses..."
326 yes | "$SDKMANAGER" --sdk_root="$ANDROID_HOME" --licenses >/dev/null || true
327
328 log "Installing Android SDK packages..."
329 "$SDKMANAGER" --sdk_root="$ANDROID_HOME" \
330 "cmdline-tools;latest" \
331 "platform-tools" \
332 "emulator" \
333 "platforms;android-36" \
334 "build-tools;36.0.0"
335
336 add_to_path_config "ANDROID_SDK" 'export ANDROID_HOME="$HOME/Android/Sdk"
337export ANDROID_SDK_ROOT="$ANDROID_HOME"
338export PATH="$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator"'
339
340 log "Android SDK installation sequence finished!"
341}
342
343# =======================================================
344# CLOUD & INFRASTRUCTURE
345# =======================================================
346
347install_docker() {
348 log "Checking Docker status..."
349
350 # 1. Install if missing
351 if ! require_cmd docker; then
352 log "Installing Docker from official source..."
353 if [[ "$OS" == "macOS" ]]; then
354 [[ "$SYS_ARCH" == "arm64" ]] && DOCKER_MAC_ARCH="arm64" || DOCKER_MAC_ARCH="amd64"
355 DMG_URL="https://desktop.docker.com/mac/main/${DOCKER_MAC_ARCH}/Docker.dmg"
356 curl -fsSL -o /tmp/Docker.dmg "$DMG_URL"
357 hdiutil attach /tmp/Docker.dmg -nobrowse -mountpoint /Volumes/Docker
358 sudo cp -a /Volumes/Docker/Docker.app /Applications/
359 hdiutil detach /Volumes/Docker
360 rm /tmp/Docker.dmg
361
362 log "Starting Docker Desktop..."
363 open /Applications/Docker.app
364 log "Please complete the setup in the Docker Desktop UI."
365 else
366 curl -fsSL https://get.docker.com | sudo sh
367 fi
368 else
369 warn "Docker is already installed. Enforcing permissions..."
370 fi
371
372 # 2. Aggressively enforce Linux permissions
373 if [[ "$OS" != "macOS" ]]; then
374 log "Applying strict Linux post-install actions..."
375
376 # Ensure docker group exists and user is added
377 sudo groupadd -f docker
378 sudo usermod -aG docker "$USER"
379
380 # Ensure services are enabled and running
381 if command -v systemctl >/dev/null 2>&1; then
382 sudo systemctl enable --now docker.service
383 sudo systemctl enable --now docker.socket containerd.service 2>/dev/null || true
384 elif [[ "$OS" == "WSL" ]]; then
385 sudo service docker start
386 fi
387
388 # Give the system a second to generate the socket file
389 sleep 2
390
391 # Lock in ownership and permissions on the socket
392 if [[ -S /var/run/docker.sock ]]; then
393 log "Securing /var/run/docker.sock..."
394 sudo chown root:docker /var/run/docker.sock
395 sudo chmod 660 /var/run/docker.sock
396 else
397 warn "Docker socket not found. The service may have failed to start."
398 fi
399
400 log "Added $USER to the docker group and secured the socket."
401 fi
402}
403
404install_aws() {
405 if require_cmd aws; then warn "AWS CLI exists"; return; fi
406 log "Installing AWS CLI directly from Amazon..."
407
408 if [[ "$OS" == "macOS" ]]; then
409 curl -fsSL -o /tmp/AWSCLIV2.pkg "https://awscli.amazonaws.com/AWSCLIV2.pkg"
410 sudo installer -pkg /tmp/AWSCLIV2.pkg -target /
411 rm /tmp/AWSCLIV2.pkg
412 else
413 if ! require_cmd unzip; then
414 err "unzip is required. Please install 'Build Tools' (Option 1) first."
415 return 1
416 fi
417 curl -fsSL -o /tmp/awscliv2.zip "https://awscli.amazonaws.com/awscli-exe-linux-${AWS_ARCH}.zip"
418 cd /tmp && unzip -q awscliv2.zip && sudo ./aws/install
419 rm -rf /tmp/awscliv2.zip /tmp/aws
420 fi
421}
422
423install_gcloud() {
424 if require_cmd gcloud; then warn "Google Cloud CLI exists"; return; fi
425 log "Installing Google Cloud CLI..."
426 curl -fsSL https://sdk.cloud.google.com | $CURRENT_SHELL -s -- --disable-prompts
427
428 if [[ "$CURRENT_SHELL" == "zsh" ]]; then
429 add_to_path_config "GCLOUD" '[ -f "$HOME/google-cloud-sdk/path.zsh.inc" ] && source "$HOME/google-cloud-sdk/path.zsh.inc"'
430 else
431 add_to_path_config "GCLOUD" '[ -f "$HOME/google-cloud-sdk/path.bash.inc" ] && source "$HOME/google-cloud-sdk/path.bash.inc"'
432 fi
433}
434
435install_firebase() {
436 if require_cmd firebase; then warn "Firebase CLI exists"; return; fi
437 log "Installing Firebase CLI via NPM to ensure ARM64 compatibility..."
438
439 if ! require_cmd npm; then
440 err "NPM not found. Please install NVM (Option 3) first."
441 return 1
442 fi
443
444 npm install -g firebase-tools
445}
446
447# =======================================================
448# DEV TOOLS & SECURITY
449# =======================================================
450
451install_gh() {
452 if require_cmd gh; then warn "GitHub CLI exists"; return; fi
453 log "Fetching latest GitHub CLI version..."
454 LATEST_GH=$(curl -s https://api.github.com/repos/cli/cli/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
455 TAR_NAME="gh_${LATEST_GH}_${OS_LOWER}_${SYS_ARCH}"
456
457 curl -fsSL -o /tmp/gh.tar.gz "https://github.com/cli/cli/releases/download/v${LATEST_GH}/${TAR_NAME}.tar.gz"
458 tar -xzf /tmp/gh.tar.gz -C /tmp
459 sudo mv "/tmp/${TAR_NAME}/bin/gh" /usr/local/bin/
460 sudo rm -rf "/tmp/${TAR_NAME}" /tmp/gh.tar.gz
461}
462
463install_infisical() {
464 if require_cmd infisical; then warn "Infisical CLI exists"; return; fi
465 log "Installing Infisical CLI via NPM..."
466
467 if ! require_cmd npm; then
468 err "NPM not found. Please install NVM (Option 3) first."
469 return 1
470 fi
471
472 npm install -g @infisical/cli
473}
474
475# =======================================================
476# AI & AGENTIC TOOLS
477# =======================================================
478
479install_claude() { log "Installing Claude Code..."; curl -fsSL https://claude.ai/install.sh | $CURRENT_SHELL; }
480install_opencode() { log "Installing OpenCode..."; curl -fsSL https://opencode.ai/install | $CURRENT_SHELL; }
481
482install_codex() {
483 log "Installing @openai/codex..."
484 if ! require_cmd npm; then err "Node.js/NPM is required. Install NVM (3) first."; return 1; fi
485 npm i -g @openai/codex
486}
487
488# =======================================================
489# MENU LOGIC
490# =======================================================
491show_menu() {
492 clear
493 printf "${BLUE}==================================================${NC}\n"
494 printf "${GREEN} DEVELOPER ENVIRONMENT INSTALLER (Polyglot) ${NC}\n"
495 printf "${BLUE}==================================================${NC}\n"
496 printf "${YELLOW}--- Core Runtimes & Managers ---${NC}\n"
497 printf " 1) Build Tools (GCC/Make)\n"
498 printf " 2) Homebrew (Optional)\n"
499 printf " 3) NVM (Node.js)\n"
500 printf " 4) Python 3 (Official API)\n"
501 printf " 5) Go (Official -> /usr/local)\n"
502 printf " 6) SDKMAN (Java/Kotlin)\n"
503 printf " 7) .NET (Official Script)\n"
504 printf " 8) Android SDK (CLI + Platform Tools)\n"
505 printf "${YELLOW}--- Cloud & Infrastructure ---${NC}\n"
506 printf " 9) Docker (Official DMG/sh)\n"
507 printf " 10) AWS CLI (Official Bin)\n"
508 printf " 11) Google Cloud CLI (gcloud)\n"
509 printf " 12) Firebase CLI (NPM/ARM64 Safe)\n"
510 printf "${YELLOW}--- Dev Tools & Security ---${NC}\n"
511 printf " 13) GitHub CLI (Official Bin)\n"
512 printf " 14) Infisical (Official Bin)\n"
513 printf "${YELLOW}--- AI & Agentic Tools ---${NC}\n"
514 printf " 15) Claude Code CLI\n"
515 printf " 16) OpenCode (opencode.ai)\n"
516 printf " 17) OpenAI Codex CLI\n"
517 printf "${BLUE}==================================================${NC}\n"
518 printf " 99) Quit & Refresh Shell\n"
519 printf "${BLUE}==================================================${NC}\n"
520}
521
522while true; do
523 show_menu
524
525 # Bulletproof prompt for both Bash and Zsh
526 printf "Select options (space-separated): "
527 read input
528
529 # Thanks to 'setopt shwordsplit' in Zsh, this behaves perfectly across both shells
530 for choice in $input; do
531 case "$choice" in
532 1) install_build_tools ;;
533 2) install_brew ;;
534 3) install_nvm ;;
535 4) install_python ;;
536 5) install_go ;;
537 6) install_sdkman ;;
538 7) install_dotnet ;;
539 8) install_android ;;
540 9) install_docker ;;
541 10) install_aws ;;
542 11) install_gcloud ;;
543 12) install_firebase ;;
544 13) install_gh ;;
545 14) install_infisical ;;
546 15) install_claude ;;
547 16) install_opencode ;;
548 17) install_codex ;;
549 99)
550 log "Installation complete! Refreshing terminal environment..."
551
552 # If on Linux, forcefully inherit the new docker group without needing a logout
553 if [[ "$OS" != "macOS" ]] && command -v sg >/dev/null 2>&1; then
554 exec sg docker -c "exec ${SHELL:-zsh}"
555 else
556 exec "${SHELL:-zsh}"
557 fi
558 ;;
559 *) warn "Option $choice not valid." ;;
560 esac
561 done
562
563 printf "Press Enter to continue..."
564 read dummy
565done
566