33
44REPO=" thinkany-ai/codeany"
55BINARY=" codeany"
6- INSTALL_DIR=" /usr/local/bin"
6+ # Install dir: always user-owned, no sudo needed
7+ INSTALL_DIR=" ${CODEANY_INSTALL_DIR:- $HOME / .local/ bin} "
78
8- # Colors (output to stderr so they don't pollute stdout captures)
99RED=' \033[0;31m'
1010GREEN=' \033[0;32m'
1111YELLOW=' \033[1;33m'
@@ -19,8 +19,8 @@ error() { printf "${RED}[codeany]${NC} ERROR: %s\n" "$1" >&2; exit 1; }
1919
2020# Detect OS and arch
2121detect_platform () {
22- OS=" $( uname -s) "
23- ARCH=" $( uname -m) "
22+ OS=" $( uname -s 2> /dev/null || echo unknown ) "
23+ ARCH=" $( uname -m 2> /dev/null || echo unknown ) "
2424
2525 case " $OS " in
2626 Linux) OS=" linux" ;;
@@ -30,81 +30,118 @@ detect_platform() {
3030 esac
3131
3232 case " $ARCH " in
33- x86_64|amd64) ARCH=" amd64" ;;
34- arm64|aarch64) ARCH=" arm64" ;;
35- armv7l) ARCH=" arm" ;;
33+ x86_64|amd64) ARCH=" amd64" ;;
34+ arm64|aarch64) ARCH=" arm64" ;;
35+ armv7l|armv6l) ARCH=" arm" ;;
3636 * ) error " Unsupported architecture: $ARCH " ;;
3737 esac
3838
3939 PLATFORM=" ${OS} _${ARCH} "
4040}
4141
42- # Get latest release version from GitHub
42+ # Get latest release version
4343get_latest_version () {
4444 if command -v curl > /dev/null 2>&1 ; then
45- VERSION=$( curl -fsSL " https://api.github.com/repos/${REPO} /releases/latest" | grep ' "tag_name"' | sed -E ' s/.*"tag_name": *"([^"]+)".*/\1/' )
45+ VERSION=$( curl -fsSL " https://api.github.com/repos/${REPO} /releases/latest" \
46+ | grep ' "tag_name"' | sed -E ' s/.*"tag_name": *"([^"]+)".*/\1/' )
4647 elif command -v wget > /dev/null 2>&1 ; then
47- VERSION=$( wget -qO- " https://api.github.com/repos/${REPO} /releases/latest" | grep ' "tag_name"' | sed -E ' s/.*"tag_name": *"([^"]+)".*/\1/' )
48+ VERSION=$( wget -qO- " https://api.github.com/repos/${REPO} /releases/latest" \
49+ | grep ' "tag_name"' | sed -E ' s/.*"tag_name": *"([^"]+)".*/\1/' )
4850 else
4951 error " curl or wget is required"
5052 fi
5153
52- if [ -z " $VERSION " ]; then
53- error " Could not determine latest version. Check https://github.com/${REPO} /releases"
54- fi
54+ [ -n " $VERSION " ] || error " Could not get latest version from GitHub. Check: https://github.com/${REPO} /releases"
5555}
5656
57- # Download binary to a temp file, print path to stdout
57+ # Download binary, return path via stdout
5858download_binary () {
59- FILENAME=" ${BINARY} _${PLATFORM} "
60- if [ " $OS " = " windows" ]; then
61- FILENAME=" ${FILENAME} .exe"
62- fi
63-
59+ EXT=" "
60+ [ " $OS " = " windows" ] && EXT=" .exe"
61+ FILENAME=" ${BINARY} _${PLATFORM}${EXT} "
6462 URL=" https://github.com/${REPO} /releases/download/${VERSION} /${FILENAME} "
63+
6564 TMP_DIR=" $( mktemp -d) "
66- TMP_FILE=" ${TMP_DIR} /${BINARY} "
65+ TMP_FILE=" ${TMP_DIR} /${BINARY}${EXT} "
6766
6867 info " Downloading ${BINARY} ${VERSION} for ${PLATFORM} ..."
69- info " URL: ${URL} "
7068
7169 if command -v curl > /dev/null 2>&1 ; then
72- curl -fsSL " $URL " -o " $TMP_FILE " || error " Download failed. Is v${VERSION} released? Check: https://github.com/${REPO} /releases"
70+ curl -fsSL " $URL " -o " $TMP_FILE " \
71+ || error " Download failed. Check releases: https://github.com/${REPO} /releases"
7372 else
74- wget -qO " $TMP_FILE " " $URL " || error " Download failed. Check: https://github.com/${REPO} /releases"
73+ wget -qO " $TMP_FILE " " $URL " \
74+ || error " Download failed. Check releases: https://github.com/${REPO} /releases"
7575 fi
7676
7777 chmod +x " $TMP_FILE "
78- # Only print the path to stdout — all other output above goes to stderr
79- printf " %s" " $TMP_FILE "
78+ printf " %s" " $TMP_FILE " # Only path goes to stdout
8079}
8180
82- # Install binary
81+ # Install binary to user dir (no sudo)
8382install_binary () {
8483 TMP_FILE=" $1 "
84+ mkdir -p " $INSTALL_DIR "
85+ mv " $TMP_FILE " " ${INSTALL_DIR} /${BINARY} "
86+ success " Installed to ${INSTALL_DIR} /${BINARY} "
87+ }
8588
86- if [ -w " $INSTALL_DIR " ]; then
87- mv " $TMP_FILE " " ${INSTALL_DIR} /${BINARY} "
88- success " Installed to ${INSTALL_DIR} /${BINARY} "
89- elif command -v sudo > /dev/null 2>&1 ; then
90- sudo mv " $TMP_FILE " " ${INSTALL_DIR} /${BINARY} "
91- success " Installed to ${INSTALL_DIR} /${BINARY} (with sudo)"
92- else
93- LOCAL_BIN=" $HOME /.local/bin"
94- mkdir -p " $LOCAL_BIN "
95- mv " $TMP_FILE " " ${LOCAL_BIN} /${BINARY} "
96- success " Installed to ${LOCAL_BIN} /${BINARY} "
97- warn " Add to PATH: export PATH=\"\$ HOME/.local/bin:\$ PATH\" "
89+ # Detect current shell config file
90+ detect_shell_config () {
91+ SHELL_NAME=" $( basename " ${SHELL:- sh} " ) "
92+ case " $SHELL_NAME " in
93+ zsh) echo " $HOME /.zshrc" ;;
94+ bash)
95+ # macOS bash uses ~/.bash_profile, Linux uses ~/.bashrc
96+ if [ " $( uname -s) " = " Darwin" ]; then
97+ echo " $HOME /.bash_profile"
98+ else
99+ echo " $HOME /.bashrc"
100+ fi
101+ ;;
102+ fish) echo " $HOME /.config/fish/config.fish" ;;
103+ * ) echo " $HOME /.profile" ;;
104+ esac
105+ }
106+
107+ # Add INSTALL_DIR to PATH in shell config if not already there
108+ add_to_path () {
109+ # Check if already in PATH
110+ case " :$PATH :" in
111+ * " :${INSTALL_DIR} :" * )
112+ return 0 # Already in PATH
113+ ;;
114+ esac
115+
116+ SHELL_CONFIG=" $( detect_shell_config) "
117+ PATH_SNIPPET=" export PATH=\" ${INSTALL_DIR} :\$ PATH\" "
118+
119+ # fish uses different syntax
120+ if [ " $( basename " ${SHELL:- sh} " ) " = " fish" ]; then
121+ PATH_SNIPPET=" fish_add_path ${INSTALL_DIR} "
98122 fi
123+
124+ # Check if already in config file
125+ if [ -f " $SHELL_CONFIG " ] && grep -qF " $INSTALL_DIR " " $SHELL_CONFIG " 2> /dev/null; then
126+ return 0
127+ fi
128+
129+ # Append to config file
130+ {
131+ printf " \n# Added by CodeAny installer\n"
132+ printf " %s\n" " $PATH_SNIPPET "
133+ } >> " $SHELL_CONFIG "
134+
135+ success " Added ${INSTALL_DIR} to PATH in ${SHELL_CONFIG} "
136+ warn " Run: source ${SHELL_CONFIG} (or open a new terminal)"
137+ NEED_SOURCE=" $SHELL_CONFIG "
99138}
100139
101140# Verify installation
102141verify_install () {
103- if command -v " $BINARY " > /dev/null 2>&1 ; then
104- INSTALLED_VERSION=$( " $BINARY " --version 2> /dev/null || echo " unknown" )
105- success " ✓ ${BINARY} installed! (${INSTALLED_VERSION} )"
106- else
107- warn " ${BINARY} installed but not in PATH. Restart your shell or run: hash -r"
142+ if PATH=" ${INSTALL_DIR} :${PATH} " command -v " $BINARY " > /dev/null 2>&1 ; then
143+ INSTALLED_VERSION=$( PATH=" ${INSTALL_DIR} :${PATH} " " $BINARY " --version 2> /dev/null || echo " installed" )
144+ success " ✓ ${BINARY} ${INSTALLED_VERSION} ready"
108145 fi
109146}
110147
@@ -115,22 +152,32 @@ main() {
115152
116153 detect_platform
117154 info " Platform: ${PLATFORM} "
155+ info " Install dir: ${INSTALL_DIR} "
118156
119157 get_latest_version
120158 info " Latest version: ${VERSION} "
121159
122160 TMP_FILE=$( download_binary)
123161 install_binary " $TMP_FILE "
162+ add_to_path
124163 verify_install
125164
126165 printf " \n" >&2
127- success " 🎉 CodeAny is ready !"
166+ success " 🎉 CodeAny ${VERSION} installed !"
128167 printf " \n" >&2
168+
169+ if [ -n " $NEED_SOURCE " ]; then
170+ printf " Activate PATH for this session:\n" >&2
171+ printf " ${YELLOW} source ${NEED_SOURCE}${NC} \n" >&2
172+ printf " \n" >&2
173+ fi
174+
129175 printf " Set your API key and start:\n" >&2
130- printf " ${YELLOW} export ANTHROPIC_API_KEY=\" sk-ant-...\" ${NC} \n" >&2
131- printf " ${GREEN} codeany${NC} \n" >&2
176+ printf " ${YELLOW} export ANTHROPIC_API_KEY=\" sk-ant-...\" ${NC} \n" >&2
177+ printf " ${GREEN} codeany${NC} \n" >&2
132178 printf " \n" >&2
133- printf " Docs: https://github.com/${REPO} \n" >&2
179+ printf " Self-update anytime:\n" >&2
180+ printf " ${GREEN} codeany update${NC} \n" >&2
134181 printf " \n" >&2
135182}
136183
0 commit comments