Created
November 28, 2025 12:36
-
-
Save darrylsepeda/7dd6fae6220e1a38dd9855f0ca1e8836 to your computer and use it in GitHub Desktop.
install
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -euo pipefail | |
| APP=mitrais-ai-coding-assistant | |
| MUTED='\033[0;2m' | |
| RED='\033[0;31m' | |
| # ORANGE='\033[38;2;255;140;0m' | |
| PURPLE='\033[0;35m' | |
| NC='\033[0m' # No Color | |
| requested_version=${VERSION:-} | |
| raw_os=$(uname -s) | |
| os=$(echo "$raw_os" | tr '[:upper:]' '[:lower:]') | |
| case "$raw_os" in | |
| Darwin*) os="darwin" ;; | |
| Linux*) os="linux" ;; | |
| MINGW*|MSYS*|CYGWIN*) os="windows" ;; | |
| esac | |
| arch=$(uname -m) | |
| if [[ "$arch" == "aarch64" ]]; then | |
| arch="arm64" | |
| fi | |
| if [[ "$arch" == "x86_64" ]]; then | |
| arch="x64" | |
| fi | |
| if [ "$os" = "darwin" ] && [ "$arch" = "x64" ]; then | |
| rosetta_flag=$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0) | |
| if [ "$rosetta_flag" = "1" ]; then | |
| arch="arm64" | |
| fi | |
| fi | |
| combo="$os-$arch" | |
| case "$combo" in | |
| linux-x64|linux-arm64|darwin-x64|darwin-arm64|windows-x64) | |
| ;; | |
| *) | |
| echo -e "${RED}Unsupported OS/Arch: $os/$arch${NC}" | |
| exit 1 | |
| ;; | |
| esac | |
| archive_ext=".zip" | |
| if [ "$os" = "linux" ]; then | |
| archive_ext=".tar.gz" | |
| fi | |
| is_musl=false | |
| if [ "$os" = "linux" ]; then | |
| if [ -f /etc/alpine-release ]; then | |
| is_musl=true | |
| fi | |
| if command -v ldd >/dev/null 2>&1; then | |
| if ldd --version 2>&1 | grep -qi musl; then | |
| is_musl=true | |
| fi | |
| fi | |
| fi | |
| needs_baseline=false | |
| if [ "$arch" = "x64" ]; then | |
| if [ "$os" = "linux" ]; then | |
| if ! grep -qi avx2 /proc/cpuinfo 2>/dev/null; then | |
| needs_baseline=true | |
| fi | |
| fi | |
| if [ "$os" = "darwin" ]; then | |
| avx2=$(sysctl -n hw.optional.avx2_0 2>/dev/null || echo 0) | |
| if [ "$avx2" != "1" ]; then | |
| needs_baseline=true | |
| fi | |
| fi | |
| fi | |
| target="$os-$arch" | |
| if [ "$needs_baseline" = "true" ]; then | |
| target="$target-baseline" | |
| fi | |
| if [ "$is_musl" = "true" ]; then | |
| target="$target-musl" | |
| fi | |
| filename="$APP-$target$archive_ext" | |
| if [ "$os" = "linux" ]; then | |
| if ! command -v tar >/dev/null 2>&1; then | |
| echo -e "${RED}Error: 'tar' is required but not installed.${NC}" | |
| exit 1 | |
| fi | |
| else | |
| if ! command -v unzip >/dev/null 2>&1; then | |
| echo -e "${RED}Error: 'unzip' is required but not installed.${NC}" | |
| exit 1 | |
| fi | |
| fi | |
| INSTALL_DIR=$HOME/.mitrais/bin | |
| mkdir -p "$INSTALL_DIR" | |
| if [ -z "$requested_version" ]; then | |
| url="https://github.com/darrylsepeda/mitrais-ai-coding-assistant/releases/latest/download/$filename" | |
| # url="https://github.com/mitrais-dev/mitrais-ai-coding-assistant/releases/latest/download/$filename" | |
| specific_version=$(curl -s https://api.github.com/repos/mitrais-dev/mitrais-ai-coding-assistant/releases/latest | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p') | |
| if [[ $? -ne 0 || -z "$specific_version" ]]; then | |
| echo -e "${RED}Failed to fetch version information${NC}" | |
| exit 1 | |
| fi | |
| else | |
| url="https://github.com/darrylsepeda/mitrais-ai-coding-assistant/releases/download/v${requested_version}/$filename" | |
| # url="https://github.com/mitrais-dev/mitrais-ai-coding-assistant/releases/download/v${requested_version}/$filename" | |
| specific_version=$requested_version | |
| fi | |
| print_message() { | |
| local level=$1 | |
| local message=$2 | |
| local color="" | |
| case $level in | |
| info) color="${PURPLE}" ;; | |
| warning) color="${NC}" ;; | |
| error) color="${RED}" ;; | |
| esac | |
| echo -e "${color}${message}${NC}" | |
| } | |
| check_version() { | |
| if command -v maica >/dev/null 2>&1; then | |
| maica_path=$(which maica) | |
| ## TODO: check if version is installed | |
| # installed_version=$(maica version) | |
| installed_version="0.0.1" | |
| installed_version=$(echo $installed_version | awk '{print $2}') | |
| if [[ "$installed_version" != "$specific_version" ]]; then | |
| print_message info "${MUTED}Installed version: ${NC}$installed_version." | |
| else | |
| print_message info "${MUTED}Version ${NC}$specific_version${MUTED} already installed" | |
| exit 0 | |
| fi | |
| fi | |
| } | |
| unbuffered_sed() { | |
| if echo | sed -u -e "" >/dev/null 2>&1; then | |
| sed -nu "$@" | |
| elif echo | sed -l -e "" >/dev/null 2>&1; then | |
| sed -nl "$@" | |
| else | |
| local pad="$(printf "\n%512s" "")" | |
| sed -ne "s/$/\\${pad}/" "$@" | |
| fi | |
| } | |
| print_progress() { | |
| local bytes="$1" | |
| local length="$2" | |
| [ "$length" -gt 0 ] || return 0 | |
| local width=50 | |
| local percent=$(( bytes * 100 / length )) | |
| [ "$percent" -gt 100 ] && percent=100 | |
| local on=$(( percent * width / 100 )) | |
| local off=$(( width - on )) | |
| local filled=$(printf "%*s" "$on" "") | |
| filled=${filled// /■} | |
| local empty=$(printf "%*s" "$off" "") | |
| empty=${empty// /・} | |
| printf "\r${PURPLE}%s%s %3d%%${NC}" "$filled" "$empty" "$percent" >&4 | |
| } | |
| download_with_progress() { | |
| local url="$1" | |
| local output="$2" | |
| if [ -t 2 ]; then | |
| exec 4>&2 | |
| else | |
| exec 4>/dev/null | |
| fi | |
| local tmp_dir=${TMPDIR:-/tmp} | |
| local basename="${tmp_dir}/maica_install_$$" | |
| local tracefile="${basename}.trace" | |
| rm -f "$tracefile" | |
| mkfifo "$tracefile" | |
| # Hide cursor | |
| printf "\033[?25l" >&4 | |
| trap "trap - RETURN; rm -f \"$tracefile\"; printf '\033[?25h' >&4; exec 4>&-" RETURN | |
| ( | |
| curl --trace-ascii "$tracefile" -s -L -o "$output" "$url" | |
| ) & | |
| local curl_pid=$! | |
| unbuffered_sed \ | |
| -e 'y/ACDEGHLNORTV/acdeghlnortv/' \ | |
| -e '/^0000: content-length:/p' \ | |
| -e '/^<= recv data/p' \ | |
| "$tracefile" | \ | |
| { | |
| local length=0 | |
| local bytes=0 | |
| while IFS=" " read -r -a line; do | |
| [ "${#line[@]}" -lt 2 ] && continue | |
| local tag="${line[0]} ${line[1]}" | |
| if [ "$tag" = "0000: content-length:" ]; then | |
| length="${line[2]}" | |
| length=$(echo "$length" | tr -d '\r') | |
| bytes=0 | |
| elif [ "$tag" = "<= recv" ]; then | |
| local size="${line[3]}" | |
| bytes=$(( bytes + size )) | |
| if [ "$length" -gt 0 ]; then | |
| print_progress "$bytes" "$length" | |
| fi | |
| fi | |
| done | |
| } | |
| wait $curl_pid | |
| local ret=$? | |
| echo "" >&4 | |
| return $ret | |
| } | |
| download_and_install() { | |
| print_message info "\n${MUTED}Installing ${NC}opencode ${MUTED}version: ${NC}$specific_version" | |
| mkdir -p opencodetmp && cd opencodetmp | |
| if [[ "$os" == "windows" ]] || ! download_with_progress "$url" "$filename"; then | |
| # Fallback to standard curl on Windows or if custom progress fails | |
| curl -# -L -o "$filename" "$url" | |
| fi | |
| if [ "$os" = "linux" ]; then | |
| tar -xzf "$filename" | |
| else | |
| unzip -q "$filename" | |
| fi | |
| mv opencode "$INSTALL_DIR" | |
| chmod 755 "${INSTALL_DIR}/opencode" | |
| cd .. && rm -rf opencodetmp | |
| } | |
| check_version | |
| download_and_install | |
| add_to_path() { | |
| local config_file=$1 | |
| local command=$2 | |
| if grep -Fxq "$command" "$config_file"; then | |
| print_message info "Command already exists in $config_file, skipping write." | |
| elif [[ -w $config_file ]]; then | |
| echo -e "\n# opencode" >> "$config_file" | |
| echo "$command" >> "$config_file" | |
| print_message info "${MUTED}Successfully added ${NC}opencode ${MUTED}to \$PATH in ${NC}$config_file" | |
| else | |
| print_message warning "Manually add the directory to $config_file (or similar):" | |
| print_message info " $command" | |
| fi | |
| } | |
| XDG_CONFIG_HOME=${XDG_CONFIG_HOME:-$HOME/.config} | |
| current_shell=$(basename "$SHELL") | |
| case $current_shell in | |
| fish) | |
| config_files="$HOME/.config/fish/config.fish" | |
| ;; | |
| zsh) | |
| config_files="$HOME/.zshrc $HOME/.zshenv $XDG_CONFIG_HOME/zsh/.zshrc $XDG_CONFIG_HOME/zsh/.zshenv" | |
| ;; | |
| bash) | |
| config_files="$HOME/.bashrc $HOME/.bash_profile $HOME/.profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile" | |
| ;; | |
| ash) | |
| config_files="$HOME/.ashrc $HOME/.profile /etc/profile" | |
| ;; | |
| sh) | |
| config_files="$HOME/.ashrc $HOME/.profile /etc/profile" | |
| ;; | |
| *) | |
| # Default case if none of the above matches | |
| config_files="$HOME/.bashrc $HOME/.bash_profile $XDG_CONFIG_HOME/bash/.bashrc $XDG_CONFIG_HOME/bash/.bash_profile" | |
| ;; | |
| esac | |
| config_file="" | |
| for file in $config_files; do | |
| if [[ -f $file ]]; then | |
| config_file=$file | |
| break | |
| fi | |
| done | |
| if [[ -z $config_file ]]; then | |
| print_message error "No config file found for $current_shell. Checked files: ${config_files[@]}" | |
| exit 1 | |
| fi | |
| if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then | |
| case $current_shell in | |
| fish) | |
| add_to_path "$config_file" "fish_add_path $INSTALL_DIR" | |
| ;; | |
| zsh) | |
| add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" | |
| ;; | |
| bash) | |
| add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" | |
| ;; | |
| ash) | |
| add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" | |
| ;; | |
| sh) | |
| add_to_path "$config_file" "export PATH=$INSTALL_DIR:\$PATH" | |
| ;; | |
| *) | |
| export PATH=$INSTALL_DIR:$PATH | |
| print_message warning "Manually add the directory to $config_file (or similar):" | |
| print_message info " export PATH=$INSTALL_DIR:\$PATH" | |
| ;; | |
| esac | |
| fi | |
| if [ -n "${GITHUB_ACTIONS-}" ] && [ "${GITHUB_ACTIONS}" == "true" ]; then | |
| echo "$INSTALL_DIR" >> $GITHUB_PATH | |
| print_message info "Added $INSTALL_DIR to \$GITHUB_PATH" | |
| fi | |
| echo -e "" | |
| echo -e "${PURPLE} VRJGIQV TPHGKRU OOOO PNMMMMMMMMMMMMMMMMMMMMNP VRJJ UPKFGJOU POON RKFEFKSV${NC}" | |
| echo -e "${PURPLE} GM VIFFFFFFFFFGFIM MHFFFFFFFFFFGJO HFFG MIFFFFFFFFFFFFFFFFFFFFGJ QJGFFFFI SKGFFFFFFFFFFFGFJN NGFGQ NJFGFFFFFFFFFGFGKR${NC}" | |
| echo -e "${PURPLE} FFHNGFFGIOV UQKGFFFGI PJGFFGJNU VPKHFFFHK HFFG TSRRRRRRRRRRRRRRRRRRRRRS NGFFFGJPW MKFFFFIMTV UOKGFFFGM NGFGQ PHFFFHIT SMIGFFFIM${NC}" | |
| echo -e "${PURPLE} FFFFFJO LGFFIFFFH WLGFFK HFFG IFFFJP OIFIO LGFFJ NGFGQ LFFGJ NL${NC}" | |
| echo -e "${PURPLE} FFFGI JFFFFGK KHFFM HFFG KIP NFFFR KGFFI NGFGQ RHFFL${NC}" | |
| echo -e "${PURPLE} FFFJR KFFGK TIFFJ HFFG JFFJN KFFJ RGFFL NGFGQ PGFFM${NC}" | |
| echo -e "${PURPLE} FFGI EFFFF IGFE HFFG JFFJN JFFK UHFFL NGFGQ IFFGN${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE HFFG JFFJN JFEE SHFFL NGFGQ KFFFHKSN${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE HFFG JFFJN JFEE KIHFFFFFFFFFFFFFFFFFFL NGFGQ UJIGFFFFFFFFFFFHHJL${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE HFFG JFFJN JFEE NGFFGLPLL TGFFL NGFGQ NLJGSRPKKGFFFFK${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE HFFG JFFJN JFEE PFFFJ EFFL NGFGQ MFFFK${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE HFFG JFFJN JFEE GFFGT FFFL NGFGQ JFFH${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE HFFG JFFJN JFEE EFFF OGFFL NGFGQ FFFG${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE HFFG JFFJN JFEE KFFHL OIFFFL NGFGQ MGLU LHFFJ${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE HFFG JFFJN JFEE IFFGIU SJFFFFFL NGFGQ NIFFFHLN WOHFFGL${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE HFFG JFFJN JFEE NHFFFFFFFFFFFFFFFHKVJFL NGFGQ SIFFFFFFEFFFFFFFFFFGLU${NC}" | |
| echo -e "${PURPLE} FFGJ FFFFF KGFE GFFG JFFJM JFFH RLIIIHFFFGIIKL VP MFFGQ OMIIJIHGHIJHLQ${NC}" | |
| echo -e "" | |
| echo -e "" | |
| echo -e "${MUTED}To get started, navigate to a project and run:${NC}" | |
| echo -e "opencode ${MUTED}Use free models${NC}" | |
| echo -e "opencode auth login ${MUTED}Add paid provider API keys${NC}" | |
| echo -e "opencode help ${MUTED}List commands and options${NC}" | |
| echo -e "" | |
| echo -e "${MUTED}For more information visit ${NC}https://opencode.ai/docs" | |
| echo -e "" | |
| echo -e "" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment