-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.sh
More file actions
executable file
·239 lines (203 loc) · 7.75 KB
/
Copy pathinstall.sh
File metadata and controls
executable file
·239 lines (203 loc) · 7.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#!/usr/bin/env bash
# crazycode installer
# Usage: curl -fsSL https://raw.githubusercontent.com/Ymx1ZQ/crazycode/main/install.sh | bash
# --all install everything without prompting
# --silent suppress interactive output (errors only)
set -euo pipefail
R='\033[0;31m' Y='\033[0;33m' C='\033[0;36m' W='\033[1;37m' D='\033[2;37m' G='\033[0;32m' X='\033[0m'
ALL=0 SILENT=0 SKIP_ALL=0
for arg in "$@"; do
case "$arg" in
--all) ALL=1 ;;
--silent) SILENT=1 ;;
esac
done
_info() { [[ $SILENT -eq 1 ]] && return; echo -e " ${C}→${X} $*"; }
_ok() { [[ $SILENT -eq 1 ]] && return; echo -e " ${G}✓${X} $*"; }
_warn() { echo -e " ${Y}⚠${X} $*"; }
_err() { echo -e " ${R}✗${X} $*" >&2; }
_section() { [[ $SILENT -eq 1 ]] && return; echo -e "\n ${D}────────────────────────────────${X}\n ${W}$*${X}"; }
_has() { command -v "$1" >/dev/null 2>&1; }
_ask() {
[[ $ALL -eq 1 ]] && return 0
[[ $SKIP_ALL -eq 1 ]] && return 1
local label="$1" desc="$2"
echo -e "\n ${W}${label}${X} ${D}${desc}${X}"
local ans
read -rp " Install? [Y/n/a/s] " ans
case "$ans" in
a|A) ALL=1; return 0 ;;
s|S) SKIP_ALL=1; return 1 ;;
n|N) return 1 ;;
*) return 0 ;;
esac
}
# Track install results for summary
declare -a TOOL_NAMES=() TOOL_RESULTS=()
_track() {
TOOL_NAMES+=("$1")
if _has "$2"; then
TOOL_RESULTS+=("ok")
else
TOOL_RESULTS+=("fail")
fi
}
_ensure_pipx() {
if ! _has pipx; then
_warn "pipx not found."
echo -e " ${D}Install it with: sudo apt install pipx${X}"
if _ask "pipx" "required by aider — install it now?"; then
sudo apt install -y pipx
pipx ensurepath
else
return 1
fi
fi
}
_ensure_npm() {
if ! _has npm; then
_warn "npm / Node.js not found."
echo -e " ${D}Recommended: install via nvm — https://github.com/nvm-sh/nvm${X}"
echo -e " ${D} curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash${X}"
echo -e " ${D} nvm install --lts${X}"
return 1
fi
}
_install_npm_tool() {
local label="$1" pkg="$2"
if _ensure_npm; then
npm i -g "$pkg"
_ok "$label installed"
else
_warn "$label skipped (npm unavailable)"
fi
}
# ─── phase 1: install crazycode ───────────────────────────────────────────────
_section "⚡ CRAZYCODE — installer"
if ! _has git; then
_err "git is required but not found. Install it first:"
_err " sudo apt install git"
exit 1
fi
CRAZYCODE_DIR="$HOME/.crazycode"
CRAZYCODE_REMOTE="https://github.com/Ymx1ZQ/crazycode.git"
# Detect a local checkout: BASH_SOURCE[0] must be a real file whose directory
# is the toplevel of a git repo and contains crazycode.sh. When piped via
# `curl … | bash`, BASH_SOURCE[0] is typically "main" (not a file), so the
# check fails and the install falls through to the GitHub clone path.
LOCAL_SRC=""
if [[ -f "${BASH_SOURCE[0]:-}" ]]; then
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" || SCRIPT_DIR=""
if [[ -n "$SCRIPT_DIR" \
&& -f "$SCRIPT_DIR/crazycode.sh" \
&& "$SCRIPT_DIR" != "$CRAZYCODE_DIR" \
&& "$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)" == "$SCRIPT_DIR" ]]; then
LOCAL_SRC="$SCRIPT_DIR"
fi
fi
if [ -d "$CRAZYCODE_DIR/.git" ]; then
_info "~/.crazycode already exists — updating..."
git -C "$CRAZYCODE_DIR" fetch --quiet
git -C "$CRAZYCODE_DIR" reset --hard "@{u}" >/dev/null 2>&1
elif [ -n "$LOCAL_SRC" ]; then
_info "Installing from local checkout at $LOCAL_SRC..."
git clone --quiet "$LOCAL_SRC" "$CRAZYCODE_DIR"
git -C "$CRAZYCODE_DIR" remote set-url origin "$CRAZYCODE_REMOTE"
else
_info "Cloning crazycode from github.com/Ymx1ZQ/crazycode..."
git clone "$CRAZYCODE_REMOTE" "$CRAZYCODE_DIR"
fi
_ok "crazycode installed"
# Detect shell and source in the right rc file
SHELL_NAME=$(basename "${SHELL:-bash}")
case "$SHELL_NAME" in
zsh) RC_FILE="$HOME/.zshrc" ;;
*) RC_FILE="$HOME/.bashrc" ;;
esac
OLD_SOURCE_LINE="source ~/.crazycode/crazycode.sh"
WRAPPER_LINE='crazycode() { source ~/.crazycode/crazycode.sh && _crazycode_main "$@"; }'
touch "$RC_FILE"
# Migrate from old source line to new wrapper
if grep -qF "$OLD_SOURCE_LINE" "$RC_FILE" && ! grep -qF "_crazycode_main" "$RC_FILE"; then
grep -vF "$OLD_SOURCE_LINE" "$RC_FILE" > "$RC_FILE.tmp"
printf '%s\n' "$WRAPPER_LINE" >> "$RC_FILE.tmp"
mv "$RC_FILE.tmp" "$RC_FILE"
_ok "Migrated ~/${RC_FILE##*/} to thin wrapper"
elif ! grep -qF "_crazycode_main" "$RC_FILE"; then
printf '\n%s\n' "$WRAPPER_LINE" >> "$RC_FILE"
_ok "Added to ~/${RC_FILE##*/}"
else
_ok "~/${RC_FILE##*/} already configured — nothing to change"
fi
# ─── phase 2: optional tools ──────────────────────────────────────────────────
if [[ $ALL -eq 0 && $SILENT -eq 0 ]]; then
echo -e "\n ${D}Y install · n skip · a install all · s skip all${X}"
fi
_section "Optional AI assistants"
# Phase 2 installs tools into $HOME/.local/bin (pipx for aider, download_cli.sh
# for goose). Both update the user's rc file but not this subshell — prepend
# the dir here so _track's command -v probe sees freshly-installed binaries.
export PATH="$HOME/.local/bin:$PATH"
if _ask "aider" "AI pair programmer in the terminal (pipx install aider-chat)"; then
if _ensure_pipx; then
pipx install aider-chat
_ok "aider installed"
else
_warn "aider skipped (pipx unavailable)"
fi
fi
_track "aider" "aider"
if _ask "claude code" "Anthropic's official AI CLI (curl installer)"; then
curl -fsSL https://claude.ai/install.sh | bash
_ok "claude code installed"
fi
_track "claude code" "claude"
if _ask "codex" "OpenAI's AI coding CLI (npm i -g @openai/codex)"; then
_install_npm_tool "codex" "@openai/codex"
fi
_track "codex" "codex"
if _ask "forge" "Tailcall's AI coding CLI (npm i -g @antinomyhq/forge)"; then
_install_npm_tool "forge" "@antinomyhq/forge"
fi
_track "forge" "forge"
if _ask "gemini cli" "Google's AI coding CLI (npm i -g @google/gemini-cli)"; then
_install_npm_tool "gemini" "@google/gemini-cli"
fi
_track "gemini" "gemini"
if _ask "goose" "AAIF's open-source AI agent (curl installer, no sudo)"; then
# CONFIGURE=false skips the upstream installer's interactive `goose configure`
# prompt — otherwise install.sh --all and the `s` skip-all flow would hang.
# Users run `goose configure` themselves on first launch to set up provider/model.
CONFIGURE=false curl -fsSL https://github.com/aaif-goose/goose/releases/download/stable/download_cli.sh | bash
_ok "goose installed"
fi
_track "goose" "goose"
if _ask "muse" "Meta's AI coding CLI (curl -fsSL https://dev.meta.ai/install.sh | bash)"; then
curl -fsSL https://dev.meta.ai/install.sh | bash
_ok "muse installed"
fi
_track "muse" "muse"
if _ask "opencode" "AI coding tool by SST (npm i -g opencode-ai@latest)"; then
_install_npm_tool "opencode" "opencode-ai@latest"
fi
_track "opencode" "opencode"
# ─── summary ─────────────────────────────────────────────────────────────────
if [[ $SILENT -eq 0 ]]; then
echo
_section "Summary"
for i in "${!TOOL_NAMES[@]}"; do
if [[ "${TOOL_RESULTS[$i]}" == "ok" ]]; then
echo -e " ${G}✓${X} ${TOOL_NAMES[$i]}"
else
echo -e " ${R}✗${X} ${TOOL_NAMES[$i]}"
fi
done
echo
fi
_ok "All done!"
echo
_info "To activate now: source ~/${RC_FILE##*/}"
_info "New terminals will have it automatically."
_info "Then type: crazycode"
_info "Future updates take effect immediately — no re-source needed."
echo