-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup.sh
More file actions
executable file
·366 lines (332 loc) · 13.5 KB
/
Copy pathsetup.sh
File metadata and controls
executable file
·366 lines (332 loc) · 13.5 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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
#!/usr/bin/env bash
#=============================================================================
# opencode-portable — self-installing, self-updating opencode config
# Repo: https://github.com/bulbaczPL/opencode-portable
#
# Usage:
# bash <(curl -sL https://git.io/opencode-portable)
# # or
# curl -sL https://git.io/opencode-portable | bash
#
# After install:
# cd ~/opencode-portable && bash setup.sh
#=============================================================================
set -euo pipefail
REPO="bulbaczPL/opencode-portable"
# shellcheck disable=SC2034
REPO_URL="https://github.com/bulbaczPL/opencode-portable.git"
INSTALL_DIR="${INSTALL_DIR:-$HOME/opencode-portable}"
CONFIG_DIR="$HOME/.config/opencode"
SYSTEMD_DIR="$HOME/.config/systemd/user"
GREEN='\033[1;32m'; YELLOW='\033[1;33m'; RED='\033[1;31m'; CYAN='\033[1;36m'; NC='\033[0m'
log() { echo -e "${CYAN}[opencode-portable]${NC} $1"; }
ok() { echo -e "${GREEN} ✓${NC} $1"; }
warn() { echo -e "${YELLOW} ⚠${NC} $1"; }
fail() { echo -e "${RED} ✗${NC} $1"; }
#=============================================================================
# AUTO-UPDATE przez gh
#=============================================================================
do_update() {
log "Sprawdzam aktualizacje..."
if [ -d "$INSTALL_DIR/.git" ]; then
cd "$INSTALL_DIR"
local old_hash
old_hash=$(git rev-parse HEAD 2>/dev/null || echo "")
git fetch origin main 2>&1 | grep -v "Already up to date" | grep -v "From" | grep -v "^$" || true
local new_hash
new_hash=$(git rev-parse origin/main 2>/dev/null || echo "")
if [ -n "$old_hash" ] && [ "$new_hash" != "$old_hash" ] && [ -n "$new_hash" ]; then
if [ -t 0 ]; then
echo -ne " Nowa wersja. Aktualizować? [Y/n] "
read -r ans
else
ans="y"
fi
if [ "$ans" != "n" ] && [ "$ans" != "N" ]; then
git pull origin main 2>&1 | tail -1
ok "Zaktualizowano do najnowszej wersji"
else
warn "Pomijam"
fi
else
ok "Masz najnowszą wersję"
fi
cd - > /dev/null
else
# Pierwsza instalacja — curl z raw (nie wymaga git/gh na czystym systemie)
log "Pobieram pliki z GitHub (curl)..."
mkdir -p "$INSTALL_DIR"
TAR_URL="https://api.github.com/repos/$REPO/tarball/main"
curl -sL "$TAR_URL" | tar xz --strip-components=1 -C "$INSTALL_DIR" 2>&1
ok "Pobrano pliki"
fi
}
#=============================================================================
# ZALEŻNOŚCI
#=============================================================================
install_deps() {
log "Sprawdzam zależności..."
if ! command -v python3 &>/dev/null; then
log "Instaluję Python 3..."
apt-get install -y python3 python3-pip >/dev/null 2>&1
fi
ok "Python: $(python3 --version)"
ok "pip: $(pip3 --version | awk '{print $2}')"
# Always ensure Node.js 22+ (Ubuntu apt gives 18 which is too old)
if command -v node &>/dev/null; then
local node_major
node_major=$(node --version 2>/dev/null | sed 's/v//' | cut -d. -f1)
if [ -n "$node_major" ] && [ "$node_major" -lt 22 ]; then
log "Aktualizuję Node.js z v$node_major do v22..."
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - &>/dev/null
apt-get install -y nodejs >/dev/null 2>&1
fi
else
log "Instaluję Node.js 22..."
curl -fsSL https://deb.nodesource.com/setup_22.x | bash - &>/dev/null
apt-get install -y nodejs >/dev/null 2>&1
fi
ok "Node.js: $(node --version)"
ok "npm: $(npm --version)"
if ! command -v git &>/dev/null; then
log "Instaluję git..."
apt-get install -y git >/dev/null 2>&1
fi
ok "git: $(git --version | awk '{print $3}')"
}
#=============================================================================
# OPENCODE CLI
#=============================================================================
install_opencode() {
log "Sprawdzam opencode..."
if command -v opencode &>/dev/null; then
ok "opencode: $(opencode --version 2>/dev/null || echo 'zainstalowany')"
else
npm install -g @opencode-ai/cli 2>&1 | tail -3
local npm_root
npm_root=$(npm root -g 2>/dev/null)
if [ -n "$npm_root" ] && [ -f "$npm_root/@opencode-ai/cli/bin/lildax" ]; then
ln -sf "$npm_root/@opencode-ai/cli/bin/lildax" /usr/local/bin/opencode 2>/dev/null || true
fi
export PATH="$PATH:/usr/local/bin"
hash -r 2>/dev/null || true
ok "opencode CLI zainstalowany"
fi
}
#=============================================================================
# G4F
#=============================================================================
install_g4f() {
log "Sprawdzam G4F..."
if python3 -c "import g4f" &>/dev/null 2>&1; then
local g4f_ver
g4f_ver=$(python3 -c "import importlib.metadata; print(importlib.metadata.version('g4f'))" 2>/dev/null || echo "zainstalowany")
ok "G4F: $g4f_ver"
else
pip3 install --break-system-packages g4f 2>&1 | tail -1
# Also install python-multipart for G4F API startup
pip3 install --break-system-packages python-multipart -q 2>/dev/null || true
ok "G4F zainstalowany"
fi
}
#=============================================================================
# KONFIGURACJA
#=============================================================================
setup_config() {
log "Konfiguruję opencode..."
mkdir -p "$CONFIG_DIR" "$CONFIG_DIR/agents" "$CONFIG_DIR/commands" "$CONFIG_DIR/skills"
# Główny config — -n = nie nadpisuj (bezpieczne dla user configu)
cp -n "$INSTALL_DIR/config/opencode.jsonc" "$CONFIG_DIR/opencode.jsonc" 2>/dev/null && ok "config skopiowany" || ok "config już istnieje"
# AGENTS.md (globalne instrukcje)
if [ -f "$INSTALL_DIR/config/AGENTS.md" ]; then
cp "$INSTALL_DIR/config/AGENTS.md" "$CONFIG_DIR/AGENTS.md" 2>/dev/null || true
ok "AGENTS.md skopiowany"
fi
# Agenci
local agent_count=0
if ls "$INSTALL_DIR/config/agents/"*.md >/dev/null 2>&1; then
cp "$INSTALL_DIR/config/agents/"*.md "$CONFIG_DIR/agents/" 2>/dev/null || true
fi
if ls "$INSTALL_DIR/agents/"*.md >/dev/null 2>&1; then
cp "$INSTALL_DIR/agents/"*.md "$CONFIG_DIR/agents/" 2>/dev/null || true
fi
agent_count=$(find "$CONFIG_DIR/agents/" -maxdepth 1 -name '*.md' 2>/dev/null | wc -l)
ok "agenty: $agent_count"
# Komendy
local cmd_count=0
if ls "$INSTALL_DIR/config/commands/"*.md >/dev/null 2>&1; then
cp "$INSTALL_DIR/config/commands/"*.md "$CONFIG_DIR/commands/" 2>/dev/null || true
fi
if ls "$INSTALL_DIR/commands/"*.md >/dev/null 2>&1; then
cp "$INSTALL_DIR/commands/"*.md "$CONFIG_DIR/commands/" 2>/dev/null || true
fi
cmd_count=$(find "$CONFIG_DIR/commands/" -maxdepth 1 -name '*.md' 2>/dev/null | wc -l)
ok "komendy: $cmd_count"
# Skille (kopiuj całe katalogi)
local skill_count=0
for skill_dir in "$INSTALL_DIR/config/skills/"*/; do
[ -d "$skill_dir" ] || continue
local name
name=$(basename "$skill_dir")
cp -r "$skill_dir" "$CONFIG_DIR/skills/$name" 2>/dev/null || true
skill_count=$((skill_count + 1))
done
if [ "$skill_count" -gt 0 ]; then
ok "skille: $skill_count"
fi
}
setup_systemd() {
log "Konfiguruję G4F service..."
local PYTHON_PATH
PYTHON_PATH=$(command -v python3 2>/dev/null || echo "python3")
mkdir -p "$SYSTEMD_DIR"
sed "s|__PYTHON_PATH__|$PYTHON_PATH|g" "$INSTALL_DIR/systemd/g4f.service" > "$SYSTEMD_DIR/g4f.service"
systemctl --user daemon-reload 2>/dev/null || { warn "systemd nie dostępny"; return; }
if systemctl --user enable --now g4f.service 2>/dev/null; then
ok "G4F aktywny"
else
warn "G4F: restart"
fi
}
test_g4f() {
sleep 3
local result
result=$(curl -sf --max-time 10 -X POST \
"http://localhost:1337/v1/chat/completions" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"hi"}],"max_tokens":3}' 2>/dev/null)
if echo "$result" | python3 -c "import sys,json; d=json.load(sys.stdin); assert d['choices'][0]['message']['content']" 2>/dev/null; then
ok "G4F działa na localhost:1337 (zwrócił odpowiedź)"
else
warn "G4F nie odpowiada lub zwraca błędy"
fi
}
start_g4f() {
# Uruchom G4F ręcznie jeśli systemd nie jest dostępne
if curl -sf -o /dev/null http://localhost:1337/v1/models --connect-timeout 2 2>/dev/null; then
ok "G4F już działa na :1337"
return 0
fi
log "Uruchamiam G4F ręcznie..."
nohup python3 -c "from g4f.api import run_api; run_api(port=1337)" > /tmp/g4f.log 2>&1 &
local pid=$!
local attempts=0
while [ "$attempts" -lt 10 ]; do
sleep 2
if curl -sf -o /dev/null http://localhost:1337/v1/models --connect-timeout 2 2>/dev/null; then
ok "G4F uruchomiony (PID $pid, after $((attempts * 2 + 2))s)"
return 0
fi
attempts=$((attempts + 1))
done
if kill -0 "$pid" 2>/dev/null; then
warn "G4F PID $pid żyje ale nie odpowiada — sprawdź /tmp/g4f.log"
else
warn "G4F nie wystartował — sprawdź /tmp/g4f.log"
fi
}
setup_env() {
local ENV_FILE="$HOME/.bash_env"
log "Sprawdzam zmienne środowiskowe..."
touch "$ENV_FILE"
# Dodaj PATH dla opencode jeśli nie istnieje
local NPM_BIN
NPM_BIN=$(npm root -g 2>/dev/null)/@opencode-ai/cli/bin
if [ -d "$NPM_BIN" ]; then
if ! grep -q "OPENCODE_PATH" "$ENV_FILE" 2>/dev/null; then
echo "# opencode-portable PATH" >> "$ENV_FILE"
echo "export PATH=\"\$PATH:$NPM_BIN\"" >> "$ENV_FILE"
ok "Dodano opencode do PATH w ~/.bash_env"
fi
fi
# Sprawdź czy ~/.bash_env jest ładowany
if ! grep -q "bash_env" "$HOME/.bashrc" 2>/dev/null; then
echo "[ -f ~/.bash_env ] && . ~/.bash_env" >> "$HOME/.bashrc"
ok "Dodano ładowanie ~/.bash_env do .bashrc"
fi
}
setup_api_keys() {
if [ ! -t 0 ]; then
warn "Non-interactive mode — pomijam konfigurację kluczy"
return
fi
echo ""
echo -e "${YELLOW}┌─────────────────────────────────────────────────────────┐${NC}"
echo -e "${YELLOW}│ Konfiguracja darmowych kluczy API (opcjonalna) │${NC}"
echo -e "${YELLOW}│ G4F + 12 modeli działa BEZ kluczy od razu! │${NC}"
echo -e "${YELLOW}│ Możesz pominąć (Enter) i dodać później przez /connect │${NC}"
echo -e "${YELLOW}└─────────────────────────────────────────────────────────┘${NC}"
echo ""
local ENV_FILE="$HOME/.bash_env"
local CONFIG_FILE="$CONFIG_DIR/opencode.jsonc"
if [ ! -f "$CONFIG_FILE" ]; then
warn "Brak opencode.jsonc — nie można dodać kluczy"
return
fi
# Mapa: nazwa providera w env → nazwa w opencode.jsonc
for entry in "GROQ:groq" "CEREBRAS:cerebras" "MISTRAL:mistral" "NVIDIA:nvidia" "OPENROUTER:openrouter"; do
local env_name="${entry%%:*}"
local config_name="${entry##*:}"
echo -ne " Dodać klucz ${CYAN}${env_name}${NC}? [Enter=pomiń] "
read -r key
if [ -z "$key" ]; then
continue
fi
local var_name="${env_name}_API_KEY"
# Dodaj/aktualizuj w .bash_env (zabezpieczony separator #)
if grep -q "$var_name" "$ENV_FILE" 2>/dev/null; then
sed -i "s#export $var_name=.*#export $var_name=\"$key\"#" "$ENV_FILE"
else
echo "export $var_name=\"$key\"" >> "$ENV_FILE"
fi
# Dodaj apiKey do opencode.jsonc (jeśli jeszcze nie ma)
if grep -q "\"$config_name\"" "$CONFIG_FILE" 2>/dev/null; then
if ! grep -q "apiKey.*${var_name}" "$CONFIG_FILE" 2>/dev/null; then
sed -i "/\"$config_name\": {/,/\"models\":/ s/\"options\": {/\"options\": {\n \"apiKey\": \"\$\{env:${var_name}\}\",/" "$CONFIG_FILE"
fi
fi
ok "$var_name dodany do ~/.bash_env i opencode.jsonc"
done
chmod 600 "$ENV_FILE"
ok "Zabezpieczono ~/.bash_env (chmod 600)"
ok "Konfiguracja kluczy zakończona"
}
summary() {
local v pc ok
v=$(cat "$INSTALL_DIR/VERSION" 2>/dev/null || echo "?")
pc="?"
if [ -f "$CONFIG_DIR/opencode.jsonc" ]; then
pip3 install --break-system-packages json5 -q 2>/dev/null || true
pc=$(python3 -c "import json5; f=open('$CONFIG_DIR/opencode.jsonc'); d=json5.load(f); print(len(d.get('provider',{})))" 2>/dev/null || echo "?")
fi
ok="OK"
command -v opencode &>/dev/null && ok="$(opencode --version 2>/dev/null)" || ok="brak"
echo ""
echo -e "${GREEN}╔══════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ opencode-portable v$v ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════════╝${NC}"
echo " G4F: $(systemctl --user is-active g4f.service 2>/dev/null || echo 'ręcznie')"
echo " opencode: $ok"
echo " Providerów: $pc"
echo " Aktualizacja: cd ~/opencode-portable && bash setup.sh"
echo ""
}
main() {
echo ""
echo -e "${CYAN}╔══════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ opencode-portable — Instalator / Aktualizator ║${NC}"
echo -e "${CYAN}╚══════════════════════════════════════════════════════╝${NC}"
echo ""
install_deps || exit 1
do_update
setup_env
install_opencode
install_g4f
setup_config
setup_systemd
start_g4f
test_g4f
setup_api_keys
summary
}
main "$@"