karnel-termux 4.7.7 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -4
- package/karnel/cli/commands/backup.sh +8 -0
- package/karnel/cli/commands/doctor/system.sh +2 -0
- package/karnel/cli/commands/doctor.sh +8 -0
- package/karnel/cli/commands/install.sh +139 -84
- package/karnel/cli/commands/list.sh +32 -0
- package/karnel/cli/commands/open.sh +10 -6
- package/karnel/cli/commands/reinstall.sh +11 -0
- package/karnel/cli/commands/robin.sh +656 -0
- package/karnel/cli/commands/show.sh +1 -0
- package/karnel/cli/commands/start.sh +5 -0
- package/karnel/cli/commands/status.sh +11 -0
- package/karnel/cli/commands/uninstall.sh +9 -0
- package/karnel/cli/commands/update.sh +9 -0
- package/karnel/cli/commands/version.sh +2 -0
- package/karnel/cli/karnel.sh +35 -25
- package/karnel/modules/dev.sh +19 -46
- package/karnel/modules/osint.sh +123 -0
- package/karnel/tools/ai/crush/install.sh +1 -1
- package/karnel/tools/ai/omni-route/install.sh +1 -1
- package/karnel/tools/deploy/railway/install.sh +1 -1
- package/karnel/tools/dev/all.sh +45 -2
- package/karnel/tools/dev/fzf/install.sh +36 -9
- package/karnel/tools/npm/turbopack/install.sh +2 -0
- package/karnel/tools/osint/all.sh +65 -0
- package/karnel/tools/osint/robin/README.md +99 -0
- package/karnel/tools/osint/robin/common.sh +258 -0
- package/karnel/tools/osint/robin/install.sh +548 -0
- package/karnel/tools/osint/robin/requirements-termux.txt +33 -0
- package/karnel/utils/env.sh +16 -2
- package/karnel/utils/tools.sh +9 -2
- package/package.json +6 -1
- package/scripts/check-package.js +45 -0
- package/scripts/completion.bash +8 -3
- package/scripts/completion.zsh +8 -1
- package/karnel/tools/dev/applaunch/__pycache__/applaunch.cpython-314.pyc +0 -0
- package/karnel/tools/dev/fconv/__pycache__/fconv.cpython-314.pyc +0 -0
- package/karnel/tools/dev/filecheck/__pycache__/filecheck.cpython-314.pyc +0 -0
- package/karnel/tools/dev/notes/__pycache__/notes.cpython-314.pyc +0 -0
- package/karnel/tools/dev/passman/__pycache__/passman.cpython-314.pyc +0 -0
- package/karnel/tools/dev/splash/__pycache__/splash.cpython-314.pyc +0 -0
- package/karnel/tools/dev/websites/__pycache__/websites.cpython-314.pyc +0 -0
- package/karnel/tools/games/arcade/__pycache__/arcade.cpython-314.pyc +0 -0
- package/karnel/tools/games/buzz/__pycache__/buzz.cpython-314.pyc +0 -0
- package/karnel/tools/games/ctfgod/__pycache__/ctfgod.cpython-314.pyc +0 -0
- package/karnel/tools/games/detective/__pycache__/detective.cpython-314.pyc +0 -0
- package/karnel/tools/games/pet-friends/__pycache__/pet-friends.cpython-314.pyc +0 -0
- package/karnel/tools/games/tamagotchi/__pycache__/tamagotchi.cpython-314.pyc +0 -0
- package/karnel/tools/games/terminal-arcade/__pycache__/terminal-arcade.cpython-314.pyc +0 -0
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
import "@/utils/log"
|
|
4
|
+
import "@/utils/version"
|
|
5
|
+
import "@/tools/osint/robin/common"
|
|
6
|
+
|
|
7
|
+
LOG_FILE="$KARNEL_CACHE/install_osint.log"
|
|
8
|
+
ROBIN_INSTALLER_DIR="$(dirname "${BASH_SOURCE[0]}")"
|
|
9
|
+
ROBIN_TERMUX_REQUIREMENTS="$ROBIN_INSTALLER_DIR/requirements-termux.txt"
|
|
10
|
+
ROBIN_STREAMLIT_VERSION="1.59.2"
|
|
11
|
+
|
|
12
|
+
_robin_package_installed() {
|
|
13
|
+
[[ "$(dpkg-query -W -f='${db:Status-Abbrev}' "$1" 2>/dev/null)" == "ii " ]]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
_robin_verify_termux() {
|
|
17
|
+
if [[ ! -x "$PREFIX/bin/pkg" ]] || [[ "$PREFIX" != *"com.termux"* ]]; then
|
|
18
|
+
log_error "Robin native installation requires a supported Termux environment"
|
|
19
|
+
return 1
|
|
20
|
+
fi
|
|
21
|
+
|
|
22
|
+
local free_kb
|
|
23
|
+
free_kb=$(df -Pk "$HOME" 2>/dev/null | awk 'NR == 2 { print $4 }')
|
|
24
|
+
if [[ "$free_kb" =~ ^[0-9]+$ ]] && (( free_kb < 400000 )); then
|
|
25
|
+
log_error "Robin requires at least 400 MB of free storage"
|
|
26
|
+
return 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
local architecture
|
|
30
|
+
architecture=$(dpkg --print-architecture 2>/dev/null || printf 'unknown')
|
|
31
|
+
if [[ "$architecture" != "aarch64" ]]; then
|
|
32
|
+
log_warn "Robin is validated on Termux aarch64; detected: $architecture"
|
|
33
|
+
fi
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
_robin_verify_python() {
|
|
37
|
+
if ! command -v python3 &>/dev/null; then
|
|
38
|
+
log_info "Installing Python..."
|
|
39
|
+
pkg install python -y &>>"$LOG_FILE" || {
|
|
40
|
+
log_error "Failed to install Python"
|
|
41
|
+
return 1
|
|
42
|
+
}
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
local version major minor
|
|
46
|
+
version=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null) || {
|
|
47
|
+
log_error "Could not determine the Python version"
|
|
48
|
+
return 1
|
|
49
|
+
}
|
|
50
|
+
major=${version%%.*}
|
|
51
|
+
minor=${version#*.}
|
|
52
|
+
if (( major < 3 || (major == 3 && minor < 10) )); then
|
|
53
|
+
log_error "Python 3.10+ is required. Found: $version"
|
|
54
|
+
return 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
python3 -c 'import venv' &>/dev/null || {
|
|
58
|
+
log_error "The Python venv module is unavailable. Reinstall the Termux python package."
|
|
59
|
+
return 1
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_robin_install_system_deps() {
|
|
64
|
+
if ! _robin_package_installed tur-repo; then
|
|
65
|
+
log_info "Enabling the Termux User Repository for native Python packages..."
|
|
66
|
+
pkg install tur-repo -y &>>"$LOG_FILE" || {
|
|
67
|
+
log_error "Failed to enable tur-repo"
|
|
68
|
+
return 1
|
|
69
|
+
}
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
local -a required_packages=(
|
|
73
|
+
git
|
|
74
|
+
tor
|
|
75
|
+
curl
|
|
76
|
+
build-essential
|
|
77
|
+
python-numpy
|
|
78
|
+
python-pandas
|
|
79
|
+
python-pillow
|
|
80
|
+
python-pyarrow
|
|
81
|
+
)
|
|
82
|
+
local -a missing_packages=()
|
|
83
|
+
local package
|
|
84
|
+
for package in "${required_packages[@]}"; do
|
|
85
|
+
_robin_package_installed "$package" || missing_packages+=("$package")
|
|
86
|
+
done
|
|
87
|
+
|
|
88
|
+
if (( ${#missing_packages[@]} > 0 )); then
|
|
89
|
+
log_info "Installing native dependencies: ${missing_packages[*]}"
|
|
90
|
+
pkg install "${missing_packages[@]}" -y &>>"$LOG_FILE" || {
|
|
91
|
+
log_error "Failed to install Robin native dependencies"
|
|
92
|
+
return 1
|
|
93
|
+
}
|
|
94
|
+
fi
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
_robin_migrate_path() {
|
|
98
|
+
local source="$1"
|
|
99
|
+
local destination="$2"
|
|
100
|
+
local label="$3"
|
|
101
|
+
[[ -e "$source" || -L "$source" ]] || return 0
|
|
102
|
+
|
|
103
|
+
if [[ ! -e "$destination" && ! -L "$destination" ]]; then
|
|
104
|
+
mv "$source" "$destination" || return 1
|
|
105
|
+
return 0
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
local migrated
|
|
109
|
+
migrated="${destination}.migrated.$(date +%Y%m%d_%H%M%S)"
|
|
110
|
+
mv "$source" "$migrated" || return 1
|
|
111
|
+
log_warn "$label already existed; legacy data was preserved at $migrated"
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
_robin_migrate_legacy_layout() {
|
|
115
|
+
_robin_refresh_layout
|
|
116
|
+
[[ "$ROBIN_LAYOUT" == "legacy" ]] || return 0
|
|
117
|
+
|
|
118
|
+
if _robin_runtime_active; then
|
|
119
|
+
log_error "Stop Robin before migrating its installation: karnel robin stop"
|
|
120
|
+
return 1
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
log_info "Migrating Robin to the managed data layout..."
|
|
124
|
+
mkdir -p "$ROBIN_CONFIG_DIR" "$ROBIN_DATA_DIR"
|
|
125
|
+
chmod 700 "$ROBIN_CONFIG_DIR" "$ROBIN_DATA_DIR" 2>/dev/null || true
|
|
126
|
+
|
|
127
|
+
_robin_migrate_path "$ROBIN_ROOT/.env" "$ROBIN_ENV_FILE" "Robin configuration" || return 1
|
|
128
|
+
_robin_migrate_path "$ROBIN_ROOT/investigations" "$ROBIN_INVESTIGATIONS_DIR" "Robin investigations" || return 1
|
|
129
|
+
|
|
130
|
+
local legacy_root="${ROBIN_ROOT}.legacy.$$"
|
|
131
|
+
mv "$ROBIN_ROOT" "$legacy_root" || return 1
|
|
132
|
+
mkdir -p "$ROBIN_ROOT" || {
|
|
133
|
+
mv "$legacy_root" "$ROBIN_ROOT"
|
|
134
|
+
return 1
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if [[ -d "$legacy_root/.venv" ]]; then
|
|
138
|
+
mv "$legacy_root/.venv" "$ROBIN_MANAGED_VENV_DIR" || {
|
|
139
|
+
rm -rf "$ROBIN_ROOT"
|
|
140
|
+
mv "$legacy_root" "$ROBIN_ROOT"
|
|
141
|
+
_robin_refresh_layout
|
|
142
|
+
_robin_prepare_persistent_data "$ROBIN_APP_DIR" || true
|
|
143
|
+
return 1
|
|
144
|
+
}
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
mv "$legacy_root" "$ROBIN_MANAGED_APP_DIR" || {
|
|
148
|
+
[[ -d "$ROBIN_MANAGED_VENV_DIR" ]] && mv "$ROBIN_MANAGED_VENV_DIR" "$legacy_root/.venv"
|
|
149
|
+
rmdir "$ROBIN_ROOT" 2>/dev/null || true
|
|
150
|
+
mv "$legacy_root" "$ROBIN_ROOT" 2>/dev/null || true
|
|
151
|
+
_robin_refresh_layout
|
|
152
|
+
_robin_prepare_persistent_data "$ROBIN_APP_DIR" || true
|
|
153
|
+
log_error "Migration failed; the legacy installation was restored"
|
|
154
|
+
return 1
|
|
155
|
+
}
|
|
156
|
+
(umask 077; printf '%s\n' "managed-by-karnel" > "$ROBIN_ROOT/.managed-by-karnel")
|
|
157
|
+
chmod 700 "$ROBIN_ROOT"
|
|
158
|
+
_robin_refresh_layout
|
|
159
|
+
_robin_prepare_persistent_data "$ROBIN_APP_DIR" || return 1
|
|
160
|
+
log_success "Robin configuration and investigations migrated without data loss"
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
_robin_prepare_persistent_data() {
|
|
164
|
+
local app_dir="$1"
|
|
165
|
+
mkdir -p "$ROBIN_CONFIG_DIR" "$ROBIN_DATA_DIR" "$ROBIN_INVESTIGATIONS_DIR"
|
|
166
|
+
chmod 700 "$ROBIN_CONFIG_DIR" "$ROBIN_DATA_DIR" "$ROBIN_INVESTIGATIONS_DIR" 2>/dev/null || true
|
|
167
|
+
|
|
168
|
+
if [[ ! -f "$ROBIN_ENV_FILE" ]]; then
|
|
169
|
+
if [[ -f "$app_dir/.env.example" ]]; then
|
|
170
|
+
cp "$app_dir/.env.example" "$ROBIN_ENV_FILE" || return 1
|
|
171
|
+
else
|
|
172
|
+
(umask 077; : > "$ROBIN_ENV_FILE") || return 1
|
|
173
|
+
fi
|
|
174
|
+
fi
|
|
175
|
+
chmod 600 "$ROBIN_ENV_FILE" || return 1
|
|
176
|
+
|
|
177
|
+
if [[ -e "$app_dir/.env" && ! -L "$app_dir/.env" ]]; then
|
|
178
|
+
_robin_migrate_path "$app_dir/.env" "$ROBIN_ENV_FILE" "Robin configuration" || return 1
|
|
179
|
+
fi
|
|
180
|
+
rm -f "$app_dir/.env"
|
|
181
|
+
ln -s "$ROBIN_ENV_FILE" "$app_dir/.env" || return 1
|
|
182
|
+
|
|
183
|
+
if [[ -e "$app_dir/investigations" && ! -L "$app_dir/investigations" ]]; then
|
|
184
|
+
_robin_migrate_path "$app_dir/investigations" "$ROBIN_INVESTIGATIONS_DIR" "Robin investigations" || return 1
|
|
185
|
+
fi
|
|
186
|
+
rm -f "$app_dir/investigations"
|
|
187
|
+
ln -s "$ROBIN_INVESTIGATIONS_DIR" "$app_dir/investigations" || return 1
|
|
188
|
+
|
|
189
|
+
if [[ -d "$app_dir/.git/info" ]]; then
|
|
190
|
+
local exclude_file="$app_dir/.git/info/exclude"
|
|
191
|
+
grep -qxF '.env' "$exclude_file" 2>/dev/null || printf '.env\n' >> "$exclude_file"
|
|
192
|
+
grep -qxF 'investigations' "$exclude_file" 2>/dev/null || printf 'investigations\n' >> "$exclude_file"
|
|
193
|
+
fi
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
_robin_clone_candidate() {
|
|
197
|
+
local app_candidate="$1"
|
|
198
|
+
log_info "Downloading Robin $ROBIN_VERSION..."
|
|
199
|
+
git clone --branch "$ROBIN_VERSION" --depth 1 "$ROBIN_REPO" "$app_candidate" &>>"$LOG_FILE" || {
|
|
200
|
+
log_error "Failed to clone Robin $ROBIN_VERSION"
|
|
201
|
+
return 1
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
local actual_commit
|
|
205
|
+
actual_commit=$(git -C "$app_candidate" rev-parse HEAD 2>/dev/null) || return 1
|
|
206
|
+
if [[ "$actual_commit" != "$ROBIN_COMMIT" ]]; then
|
|
207
|
+
log_error "Robin source verification failed"
|
|
208
|
+
log_error "Expected $ROBIN_COMMIT but received $actual_commit"
|
|
209
|
+
return 1
|
|
210
|
+
fi
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
_robin_create_venv() {
|
|
214
|
+
local venv_candidate="$1"
|
|
215
|
+
log_info "Creating the Robin Python environment..."
|
|
216
|
+
python3 -m venv --system-site-packages "$venv_candidate" &>>"$LOG_FILE" || {
|
|
217
|
+
log_error "Failed to create the Robin virtual environment"
|
|
218
|
+
return 1
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
_robin_install_python_deps() {
|
|
223
|
+
local venv_dir="$1"
|
|
224
|
+
local python="$venv_dir/bin/python"
|
|
225
|
+
[[ -x "$python" ]] || return 1
|
|
226
|
+
[[ -f "$ROBIN_TERMUX_REQUIREMENTS" ]] || {
|
|
227
|
+
log_error "Missing Termux requirements: $ROBIN_TERMUX_REQUIREMENTS"
|
|
228
|
+
return 1
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
log_info "Installing Robin Python dependencies..."
|
|
232
|
+
"$python" -m pip install --upgrade pip setuptools wheel &>>"$LOG_FILE" || return 1
|
|
233
|
+
"$python" -m pip install -r "$ROBIN_TERMUX_REQUIREMENTS" &>>"$LOG_FILE" || return 1
|
|
234
|
+
|
|
235
|
+
# Termux supplies pyarrow 25 natively. Streamlit's current metadata still
|
|
236
|
+
# caps pyarrow below 25, although Robin does not use Arrow-specific APIs.
|
|
237
|
+
"$python" -m pip install --no-deps "streamlit==$ROBIN_STREAMLIT_VERSION" &>>"$LOG_FILE" || return 1
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
_robin_verify_install() {
|
|
241
|
+
local app_dir="${1:-$ROBIN_APP_DIR}"
|
|
242
|
+
local venv_dir="${2:-$ROBIN_VENV_DIR}"
|
|
243
|
+
local python="$venv_dir/bin/python"
|
|
244
|
+
[[ -x "$python" && -f "$app_dir/ui.py" ]] || return 1
|
|
245
|
+
"$venv_dir/bin/pip" --version &>>"$LOG_FILE" || return 1
|
|
246
|
+
"$venv_dir/bin/streamlit" --version &>>"$LOG_FILE" || return 1
|
|
247
|
+
|
|
248
|
+
PYTHONPATH="$app_dir" "$python" -c '
|
|
249
|
+
import altair
|
|
250
|
+
import bs4
|
|
251
|
+
import dotenv
|
|
252
|
+
import itsdangerous
|
|
253
|
+
import langchain_anthropic
|
|
254
|
+
import langchain_community
|
|
255
|
+
import langchain_google_genai
|
|
256
|
+
import langchain_ollama
|
|
257
|
+
import langchain_openai
|
|
258
|
+
import numpy
|
|
259
|
+
import pandas
|
|
260
|
+
import PIL
|
|
261
|
+
import pyarrow
|
|
262
|
+
import pydeck
|
|
263
|
+
import requests
|
|
264
|
+
import socks
|
|
265
|
+
import streamlit
|
|
266
|
+
import health
|
|
267
|
+
import llm
|
|
268
|
+
import llm_utils
|
|
269
|
+
import scrape
|
|
270
|
+
import search
|
|
271
|
+
' &>>"$LOG_FILE" || return 1
|
|
272
|
+
|
|
273
|
+
local source
|
|
274
|
+
for source in "$app_dir"/*.py; do
|
|
275
|
+
"$python" -m py_compile "$source" &>>"$LOG_FILE" || return 1
|
|
276
|
+
done
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
_robin_relocate_venv() {
|
|
280
|
+
local old_path="$1"
|
|
281
|
+
local new_path="$2"
|
|
282
|
+
"$new_path/bin/python" - "$old_path" "$new_path" <<'PY'
|
|
283
|
+
from pathlib import Path
|
|
284
|
+
import sys
|
|
285
|
+
|
|
286
|
+
old = sys.argv[1].encode()
|
|
287
|
+
new = sys.argv[2].encode()
|
|
288
|
+
for path in (Path(sys.argv[2]) / "bin").iterdir():
|
|
289
|
+
if path.is_symlink() or not path.is_file():
|
|
290
|
+
continue
|
|
291
|
+
try:
|
|
292
|
+
content = path.read_bytes()
|
|
293
|
+
except OSError:
|
|
294
|
+
continue
|
|
295
|
+
if old in content:
|
|
296
|
+
path.write_bytes(content.replace(old, new))
|
|
297
|
+
PY
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
_robin_candidate_health() {
|
|
301
|
+
local app_dir="$1"
|
|
302
|
+
local venv_dir="$2"
|
|
303
|
+
local python="$venv_dir/bin/python"
|
|
304
|
+
local port
|
|
305
|
+
port=$(
|
|
306
|
+
"$python" -c 'import socket; s=socket.socket(); s.bind(("127.0.0.1", 0)); print(s.getsockname()[1]); s.close()'
|
|
307
|
+
) || return 1
|
|
308
|
+
|
|
309
|
+
local test_log="$ROBIN_ROOT/.health-check.log"
|
|
310
|
+
(
|
|
311
|
+
cd "$app_dir" || exit 1
|
|
312
|
+
"$python" -m streamlit run ui.py \
|
|
313
|
+
--server.address 127.0.0.1 \
|
|
314
|
+
--server.port "$port" \
|
|
315
|
+
--server.headless true \
|
|
316
|
+
--server.fileWatcherType none \
|
|
317
|
+
--browser.gatherUsageStats false
|
|
318
|
+
) &>"$test_log" &
|
|
319
|
+
local pid=$!
|
|
320
|
+
|
|
321
|
+
local healthy=false
|
|
322
|
+
local attempt
|
|
323
|
+
for ((attempt = 0; attempt < 45; attempt++)); do
|
|
324
|
+
if ! kill -0 "$pid" 2>/dev/null; then
|
|
325
|
+
break
|
|
326
|
+
fi
|
|
327
|
+
if curl --fail --silent --max-time 2 "http://127.0.0.1:$port/_stcore/health" 2>/dev/null | grep -qx "ok"; then
|
|
328
|
+
healthy=true
|
|
329
|
+
break
|
|
330
|
+
fi
|
|
331
|
+
sleep 1
|
|
332
|
+
done
|
|
333
|
+
|
|
334
|
+
kill "$pid" 2>/dev/null || true
|
|
335
|
+
for ((attempt = 0; attempt < 10; attempt++)); do
|
|
336
|
+
kill -0 "$pid" 2>/dev/null || break
|
|
337
|
+
sleep 1
|
|
338
|
+
done
|
|
339
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
340
|
+
kill -9 "$pid" 2>/dev/null || true
|
|
341
|
+
fi
|
|
342
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
343
|
+
log_error "Could not terminate the temporary Streamlit health process"
|
|
344
|
+
return 1
|
|
345
|
+
fi
|
|
346
|
+
wait "$pid" 2>/dev/null || true
|
|
347
|
+
if $healthy; then
|
|
348
|
+
rm -f "$test_log"
|
|
349
|
+
return 0
|
|
350
|
+
fi
|
|
351
|
+
|
|
352
|
+
log_error "Streamlit health check failed. Details: $test_log"
|
|
353
|
+
return 1
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
_robin_swap_candidate() {
|
|
357
|
+
local app_candidate="$1"
|
|
358
|
+
local venv_candidate="$2"
|
|
359
|
+
local app_backup="$ROBIN_ROOT/.app-backup.$$"
|
|
360
|
+
local venv_backup="$ROBIN_ROOT/.venv-backup.$$"
|
|
361
|
+
|
|
362
|
+
local had_app=false
|
|
363
|
+
local had_venv=false
|
|
364
|
+
if [[ -d "$ROBIN_MANAGED_APP_DIR" ]]; then
|
|
365
|
+
mv "$ROBIN_MANAGED_APP_DIR" "$app_backup" || {
|
|
366
|
+
log_error "Could not back up the active Robin source"
|
|
367
|
+
return 1
|
|
368
|
+
}
|
|
369
|
+
had_app=true
|
|
370
|
+
fi
|
|
371
|
+
if [[ -d "$ROBIN_MANAGED_VENV_DIR" ]]; then
|
|
372
|
+
if ! mv "$ROBIN_MANAGED_VENV_DIR" "$venv_backup"; then
|
|
373
|
+
$had_app && mv "$app_backup" "$ROBIN_MANAGED_APP_DIR"
|
|
374
|
+
log_error "Could not back up the active Robin environment"
|
|
375
|
+
return 1
|
|
376
|
+
fi
|
|
377
|
+
had_venv=true
|
|
378
|
+
fi
|
|
379
|
+
|
|
380
|
+
if ! mv "$app_candidate" "$ROBIN_MANAGED_APP_DIR"; then
|
|
381
|
+
$had_app && mv "$app_backup" "$ROBIN_MANAGED_APP_DIR"
|
|
382
|
+
$had_venv && mv "$venv_backup" "$ROBIN_MANAGED_VENV_DIR"
|
|
383
|
+
log_error "Failed to activate the new Robin source; previous version restored"
|
|
384
|
+
return 1
|
|
385
|
+
fi
|
|
386
|
+
if ! mv "$venv_candidate" "$ROBIN_MANAGED_VENV_DIR"; then
|
|
387
|
+
rm -rf "$ROBIN_MANAGED_APP_DIR"
|
|
388
|
+
$had_app && mv "$app_backup" "$ROBIN_MANAGED_APP_DIR"
|
|
389
|
+
$had_venv && mv "$venv_backup" "$ROBIN_MANAGED_VENV_DIR"
|
|
390
|
+
log_error "Failed to activate the new Robin installation; previous version restored"
|
|
391
|
+
return 1
|
|
392
|
+
fi
|
|
393
|
+
|
|
394
|
+
if ! _robin_relocate_venv "$venv_candidate" "$ROBIN_MANAGED_VENV_DIR"; then
|
|
395
|
+
rm -rf "$ROBIN_MANAGED_APP_DIR" "$ROBIN_MANAGED_VENV_DIR"
|
|
396
|
+
[[ -d "$app_backup" ]] && mv "$app_backup" "$ROBIN_MANAGED_APP_DIR"
|
|
397
|
+
[[ -d "$venv_backup" ]] && mv "$venv_backup" "$ROBIN_MANAGED_VENV_DIR"
|
|
398
|
+
log_error "Failed to relocate the Robin environment; previous version restored"
|
|
399
|
+
return 1
|
|
400
|
+
fi
|
|
401
|
+
|
|
402
|
+
_robin_refresh_layout
|
|
403
|
+
if ! _robin_verify_install; then
|
|
404
|
+
rm -rf "$ROBIN_MANAGED_APP_DIR" "$ROBIN_MANAGED_VENV_DIR"
|
|
405
|
+
[[ -d "$app_backup" ]] && mv "$app_backup" "$ROBIN_MANAGED_APP_DIR"
|
|
406
|
+
[[ -d "$venv_backup" ]] && mv "$venv_backup" "$ROBIN_MANAGED_VENV_DIR"
|
|
407
|
+
_robin_refresh_layout
|
|
408
|
+
log_error "Final Robin verification failed; previous version restored"
|
|
409
|
+
return 1
|
|
410
|
+
fi
|
|
411
|
+
|
|
412
|
+
rm -rf "$app_backup" "$venv_backup"
|
|
413
|
+
(umask 077; printf 'version=%s\ncommit=%s\n' "$ROBIN_VERSION" "$ROBIN_COMMIT" > "$ROBIN_ROOT/.managed-by-karnel")
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
_robin_install_release() {
|
|
417
|
+
_robin_verify_termux || return 1
|
|
418
|
+
_robin_verify_python || return 1
|
|
419
|
+
_robin_install_system_deps || return 1
|
|
420
|
+
_robin_migrate_legacy_layout || return 1
|
|
421
|
+
|
|
422
|
+
if _robin_runtime_active; then
|
|
423
|
+
log_error "Stop Robin before changing its installation: karnel robin stop"
|
|
424
|
+
return 1
|
|
425
|
+
fi
|
|
426
|
+
|
|
427
|
+
mkdir -p "$ROBIN_ROOT" "$KARNEL_CACHE"
|
|
428
|
+
chmod 700 "$ROBIN_ROOT" 2>/dev/null || true
|
|
429
|
+
local app_candidate="$ROBIN_ROOT/.app-candidate.$$"
|
|
430
|
+
local venv_candidate="$ROBIN_ROOT/.venv-candidate.$$"
|
|
431
|
+
rm -rf "$app_candidate" "$venv_candidate"
|
|
432
|
+
|
|
433
|
+
if ! _robin_clone_candidate "$app_candidate" ||
|
|
434
|
+
! _robin_prepare_persistent_data "$app_candidate" ||
|
|
435
|
+
! _robin_create_venv "$venv_candidate" ||
|
|
436
|
+
! _robin_install_python_deps "$venv_candidate" ||
|
|
437
|
+
! _robin_verify_install "$app_candidate" "$venv_candidate" ||
|
|
438
|
+
! _robin_candidate_health "$app_candidate" "$venv_candidate"; then
|
|
439
|
+
rm -rf "$app_candidate" "$venv_candidate"
|
|
440
|
+
log_error "Robin installation failed without changing the active version"
|
|
441
|
+
log_info "Installation log: $LOG_FILE"
|
|
442
|
+
return 1
|
|
443
|
+
fi
|
|
444
|
+
|
|
445
|
+
_robin_swap_candidate "$app_candidate" "$venv_candidate"
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
_robin_current_release() {
|
|
449
|
+
_robin_refresh_layout
|
|
450
|
+
[[ "$ROBIN_LAYOUT" == "managed" ]] || return 1
|
|
451
|
+
[[ -d "$ROBIN_APP_DIR/.git" ]] || return 1
|
|
452
|
+
[[ "$(git -C "$ROBIN_APP_DIR" rev-parse HEAD 2>/dev/null)" == "$ROBIN_COMMIT" ]] || return 1
|
|
453
|
+
_robin_verify_install
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
_robin_show_success() {
|
|
457
|
+
echo
|
|
458
|
+
box "Robin instalado com sucesso"
|
|
459
|
+
echo
|
|
460
|
+
log_success "Release validada: $ROBIN_VERSION"
|
|
461
|
+
log_info "Configure um provedor: karnel robin config"
|
|
462
|
+
log_info "Execute o diagnostico: karnel robin doctor"
|
|
463
|
+
log_info "Inicie a interface: karnel robin start"
|
|
464
|
+
log_info "Abra: http://127.0.0.1:$ROBIN_PORT"
|
|
465
|
+
echo
|
|
466
|
+
log_info "Configuracao e investigacoes ficam fora do codigo e sobrevivem a reinstalacoes."
|
|
467
|
+
echo
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
install_robin() {
|
|
471
|
+
mkdir -p "$(dirname "$LOG_FILE")"
|
|
472
|
+
_robin_acquire_lock || return 1
|
|
473
|
+
if _robin_current_release; then
|
|
474
|
+
log_info "Robin $ROBIN_VERSION is already installed and healthy"
|
|
475
|
+
_robin_release_lock
|
|
476
|
+
return 2
|
|
477
|
+
fi
|
|
478
|
+
|
|
479
|
+
local rc=0
|
|
480
|
+
log_info "Installing Robin $ROBIN_VERSION..."
|
|
481
|
+
_robin_install_release || rc=$?
|
|
482
|
+
_robin_release_lock
|
|
483
|
+
if (( rc == 0 )); then
|
|
484
|
+
_robin_show_success
|
|
485
|
+
fi
|
|
486
|
+
return "$rc"
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
uninstall_robin() {
|
|
490
|
+
_robin_refresh_layout
|
|
491
|
+
if [[ ! -d "$ROBIN_APP_DIR" && ! -d "$ROBIN_VENV_DIR" ]]; then
|
|
492
|
+
log_info "Robin is not installed"
|
|
493
|
+
return 2
|
|
494
|
+
fi
|
|
495
|
+
|
|
496
|
+
_robin_acquire_lock || return 1
|
|
497
|
+
local rc=0
|
|
498
|
+
_robin_migrate_legacy_layout || rc=$?
|
|
499
|
+
if (( rc == 0 )) && _robin_runtime_active; then
|
|
500
|
+
log_error "Stop Robin before uninstalling it: karnel robin stop"
|
|
501
|
+
rc=1
|
|
502
|
+
fi
|
|
503
|
+
|
|
504
|
+
if (( rc == 0 )); then
|
|
505
|
+
rm -rf "$ROBIN_MANAGED_APP_DIR" "$ROBIN_MANAGED_VENV_DIR"
|
|
506
|
+
rm -f "$ROBIN_PID_FILE"
|
|
507
|
+
log_success "Robin application removed"
|
|
508
|
+
log_info "Configuration preserved at: $ROBIN_CONFIG_DIR"
|
|
509
|
+
log_info "Investigations preserved at: $ROBIN_INVESTIGATIONS_DIR"
|
|
510
|
+
fi
|
|
511
|
+
_robin_release_lock
|
|
512
|
+
return "$rc"
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
update_robin() {
|
|
516
|
+
_robin_refresh_layout
|
|
517
|
+
if [[ ! -d "$ROBIN_APP_DIR" ]]; then
|
|
518
|
+
log_error "Robin is not installed. Run: karnel install osint --robin"
|
|
519
|
+
return 1
|
|
520
|
+
fi
|
|
521
|
+
_robin_acquire_lock || return 1
|
|
522
|
+
if _robin_current_release; then
|
|
523
|
+
log_info "Robin $ROBIN_VERSION is already up to date and healthy"
|
|
524
|
+
_robin_release_lock
|
|
525
|
+
return 2
|
|
526
|
+
fi
|
|
527
|
+
|
|
528
|
+
local rc=0
|
|
529
|
+
log_info "Reconciling Robin with pinned release $ROBIN_VERSION..."
|
|
530
|
+
_robin_install_release || rc=$?
|
|
531
|
+
_robin_release_lock
|
|
532
|
+
if (( rc == 0 )); then
|
|
533
|
+
log_success "Robin updated to $ROBIN_VERSION"
|
|
534
|
+
fi
|
|
535
|
+
return "$rc"
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
reinstall_robin() {
|
|
539
|
+
_robin_acquire_lock || return 1
|
|
540
|
+
local rc=0
|
|
541
|
+
log_info "Reinstalling Robin $ROBIN_VERSION without deleting user data..."
|
|
542
|
+
_robin_install_release || rc=$?
|
|
543
|
+
_robin_release_lock
|
|
544
|
+
if (( rc == 0 )); then
|
|
545
|
+
_robin_show_success
|
|
546
|
+
fi
|
|
547
|
+
return "$rc"
|
|
548
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Pure-Python dependencies tested with Robin v2.8 on Termux.
|
|
2
|
+
# Native numpy, pandas, Pillow and pyarrow come from pkg.
|
|
3
|
+
beautifulsoup4>=4.12,<5
|
|
4
|
+
PySocks>=1.7,<2
|
|
5
|
+
requests>=2.32,<3
|
|
6
|
+
python-dotenv>=1.0,<2
|
|
7
|
+
backports.tarfile>=1.2,<2
|
|
8
|
+
langchain-openai>=0.3,<2
|
|
9
|
+
langchain-ollama>=0.3,<2
|
|
10
|
+
langchain-anthropic>=0.3,<2
|
|
11
|
+
langchain-community>=0.3,<2
|
|
12
|
+
langchain-google-genai>=2,<5
|
|
13
|
+
altair>=4,<7
|
|
14
|
+
blinker>=1.5,<2
|
|
15
|
+
cachetools>=5.5,<8
|
|
16
|
+
click>=7,<9
|
|
17
|
+
gitpython>=3.0.7,<4
|
|
18
|
+
packaging>=20
|
|
19
|
+
protobuf>=3.20,<8
|
|
20
|
+
pydeck>=0.8.0b4,<1
|
|
21
|
+
rich>=11
|
|
22
|
+
tenacity>=8.1,<10
|
|
23
|
+
toml>=0.10.1,<2
|
|
24
|
+
tornado>=6.0,<7
|
|
25
|
+
typing-extensions>=4.10,<5
|
|
26
|
+
watchdog>=2.1.5,<7
|
|
27
|
+
starlette>=0.40
|
|
28
|
+
uvicorn>=0.30
|
|
29
|
+
httptools>=0.6.3
|
|
30
|
+
anyio>=4
|
|
31
|
+
python-multipart>=0.0.10
|
|
32
|
+
websockets>=12
|
|
33
|
+
itsdangerous>=2.1.2
|
package/karnel/utils/env.sh
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
|
|
3
|
-
KARNEL_VERSION="4.
|
|
3
|
+
KARNEL_VERSION="4.8.0"
|
|
4
4
|
|
|
5
5
|
# -------------------------
|
|
6
6
|
# Directorios del usuario
|
|
@@ -23,6 +23,9 @@ KARNEL_BIN="$KARNEL_PATH/bin"
|
|
|
23
23
|
KARNEL_MODULES="$KARNEL_PATH/modules"
|
|
24
24
|
KARNEL_UTILS="$KARNEL_PATH/utils"
|
|
25
25
|
KARNEL_CLI="$KARNEL_PATH/cli"
|
|
26
|
+
KARNEL_TOOLS="$KARNEL_DATA/tools"
|
|
27
|
+
KARNEL_RUN="$KARNEL_CACHE/run"
|
|
28
|
+
KARNEL_LOGS="$KARNEL_CACHE/logs"
|
|
26
29
|
|
|
27
30
|
# -------------------------
|
|
28
31
|
# Crear directorios
|
|
@@ -31,7 +34,18 @@ KARNEL_CLI="$KARNEL_PATH/cli"
|
|
|
31
34
|
mkdir -p \
|
|
32
35
|
"$KARNEL_CONFIG" \
|
|
33
36
|
"$KARNEL_CACHE" \
|
|
34
|
-
"$KARNEL_DATA"
|
|
37
|
+
"$KARNEL_DATA" \
|
|
38
|
+
"$KARNEL_TOOLS" \
|
|
39
|
+
"$KARNEL_RUN" \
|
|
40
|
+
"$KARNEL_LOGS"
|
|
41
|
+
|
|
42
|
+
chmod 700 \
|
|
43
|
+
"$KARNEL_CONFIG" \
|
|
44
|
+
"$KARNEL_CACHE" \
|
|
45
|
+
"$KARNEL_DATA" \
|
|
46
|
+
"$KARNEL_TOOLS" \
|
|
47
|
+
"$KARNEL_RUN" \
|
|
48
|
+
"$KARNEL_LOGS" 2>/dev/null || true
|
|
35
49
|
|
|
36
50
|
# -------------------------
|
|
37
51
|
# TUI Colors - Ruby & Obsidian
|
package/karnel/utils/tools.sh
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
1
3
|
_batch_tool_action() {
|
|
2
4
|
local module="$1"
|
|
3
5
|
local action="$2"
|
|
@@ -5,6 +7,7 @@ _batch_tool_action() {
|
|
|
5
7
|
local -a tools=("$@")
|
|
6
8
|
local success_count=0
|
|
7
9
|
local failed_count=0
|
|
10
|
+
local skipped_count=0
|
|
8
11
|
|
|
9
12
|
import "@/tools/$module/all"
|
|
10
13
|
|
|
@@ -14,7 +17,8 @@ _batch_tool_action() {
|
|
|
14
17
|
"$func_name"
|
|
15
18
|
case $? in
|
|
16
19
|
0) ((success_count++));;
|
|
17
|
-
|
|
20
|
+
2) ((skipped_count++));;
|
|
21
|
+
*) ((failed_count++));;
|
|
18
22
|
esac
|
|
19
23
|
else
|
|
20
24
|
log_warn "Unknown $module tool: $tool"
|
|
@@ -29,6 +33,9 @@ _batch_tool_action() {
|
|
|
29
33
|
if [[ $failed_count -gt 0 ]]; then
|
|
30
34
|
log_warn "$failed_count tool(s) failed to ${action}"
|
|
31
35
|
fi
|
|
36
|
+
if [[ $skipped_count -gt 0 ]]; then
|
|
37
|
+
log_info "$skipped_count tool(s) already in the requested state"
|
|
38
|
+
fi
|
|
32
39
|
|
|
33
|
-
|
|
40
|
+
(( failed_count == 0 ))
|
|
34
41
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "karnel-termux",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
4
4
|
"description": "Modular Dev Environment for Termux — install languages, databases, AI agents, editors, and more with one command",
|
|
5
5
|
"bin": {
|
|
6
6
|
"karnel": "karnel/bin/karnel"
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
"LICENSE"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
+
"check:syntax": "bash tests/check-syntax.sh",
|
|
17
|
+
"lint:shell": "bash tests/check-shellcheck.sh",
|
|
18
|
+
"test": "bash tests/run.sh",
|
|
19
|
+
"pack:check": "node scripts/check-package.js",
|
|
20
|
+
"ci": "npm run lint:shell && npm test && npm run pack:check",
|
|
16
21
|
"postinstall": "node scripts/npm-install.js"
|
|
17
22
|
},
|
|
18
23
|
"engines": {
|