karnel-termux 4.9.4 → 4.9.6
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 +31 -1
- package/karnel/cli/commands/brain.sh +9 -2
- package/karnel/cli/commands/install.sh +11 -0
- package/karnel/cli/commands/list.sh +32 -0
- package/karnel/cli/commands/open.sh +6 -0
- package/karnel/cli/commands/plugin.sh +110 -0
- package/karnel/cli/commands/reinstall.sh +8 -0
- package/karnel/cli/commands/show.sh +7 -1
- package/karnel/cli/commands/uninstall.sh +8 -0
- package/karnel/cli/commands/update.sh +8 -0
- package/karnel/cli/karnel.sh +14 -6
- package/karnel/modules/plugin.sh +34 -0
- package/karnel/modules/security.sh +22 -0
- package/karnel/tools/ai/engram/install.sh +13 -9
- package/karnel/tools/ai/hermes-agent/install.sh +4 -1
- package/karnel/tools/ai/kiro/install.sh +10 -4
- package/karnel/tools/ai/opencode/install.sh +38 -131
- package/karnel/tools/lang/bun/src/bun-shim.c +28 -7
- package/karnel/tools/plugins/install.sh +150 -0
- package/karnel/tools/security/all.sh +42 -0
- package/karnel/tools/security/template.sh +35 -0
- package/karnel/utils/banner.sh +36 -22
- package/karnel/utils/bootstrap.sh +16 -6
- package/karnel/utils/env.sh +2 -1
- package/karnel/utils/install.sh +107 -0
- package/karnel/utils/proot.sh +26 -0
- package/package.json +1 -1
|
@@ -3,54 +3,18 @@
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
5
|
import "@/utils/colors"
|
|
6
|
+
import "@/utils/proot"
|
|
7
|
+
import "@/utils/install"
|
|
6
8
|
|
|
7
9
|
LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
8
10
|
OPENCODE_DATA_DIR="$HOME/.local/share/karnel-data/opencode"
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
root="$(find /data/data/com.termux -maxdepth 10 -type d \
|
|
13
|
-
-name "rootfs" -path "*/containers/ubuntu/*" 2>/dev/null | head -1)"
|
|
14
|
-
|
|
15
|
-
if [ -z "$root" ]; then
|
|
16
|
-
root="$(find /data/data/com.termux -maxdepth 10 -type d \
|
|
17
|
-
-name "ubuntu" -path "*/installed-rootfs/*" 2>/dev/null | head -1)"
|
|
18
|
-
fi
|
|
19
|
-
|
|
20
|
-
echo "$root"
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
_opencode_proot_ubuntu() {
|
|
24
|
-
proot-distro login \
|
|
25
|
-
--shared-tmp \
|
|
26
|
-
ubuntu \
|
|
27
|
-
-- "$@"
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
_get_latest_opencode_version() {
|
|
31
|
-
curl -fsSL https://api.github.com/repos/anomalyco/opencode/releases/latest |
|
|
32
|
-
grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/'
|
|
12
|
+
_install_opencode_deps() {
|
|
13
|
+
loading "Installing glibc and dependencies" _install_opencode_deps_impl
|
|
33
14
|
}
|
|
34
15
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
_opencode_install_deps_native_impl() {
|
|
40
|
-
if [[ ! -f $PREFIX/etc/apt/sources.list.d/glibc.list ]]; then
|
|
41
|
-
if ! pkg install glibc-repo -y &>>"$LOG_FILE"; then
|
|
42
|
-
log_error "Failed to install glibc-repo"
|
|
43
|
-
return 1
|
|
44
|
-
fi
|
|
45
|
-
fi
|
|
46
|
-
|
|
47
|
-
if [[ ! -f $PREFIX/glibc/lib/libc.so.6 ]]; then
|
|
48
|
-
if ! pkg install glibc -y &>>"$LOG_FILE"; then
|
|
49
|
-
log_error "Failed to install glibc"
|
|
50
|
-
return 1
|
|
51
|
-
fi
|
|
52
|
-
fi
|
|
53
|
-
|
|
16
|
+
_install_opencode_deps_impl() {
|
|
17
|
+
install_glibc || return 1
|
|
54
18
|
declare -A DEPS=(
|
|
55
19
|
["git"]="git"
|
|
56
20
|
["ripgrep"]="rg"
|
|
@@ -61,18 +25,7 @@ _opencode_install_deps_native_impl() {
|
|
|
61
25
|
["curl"]="curl"
|
|
62
26
|
["tar"]="tar"
|
|
63
27
|
)
|
|
64
|
-
|
|
65
|
-
local pkg_name bin_name
|
|
66
|
-
for pkg_name in "${!DEPS[@]}"; do
|
|
67
|
-
bin_name="${DEPS[$pkg_name]}"
|
|
68
|
-
if ! command -v "$bin_name" &>/dev/null; then
|
|
69
|
-
if ! pkg install "$pkg_name" -y &>>"$LOG_FILE"; then
|
|
70
|
-
log_error "Failed to install $pkg_name"
|
|
71
|
-
return 1
|
|
72
|
-
fi
|
|
73
|
-
fi
|
|
74
|
-
done
|
|
75
|
-
|
|
28
|
+
install_deps DEPS || return 1
|
|
76
29
|
return 0
|
|
77
30
|
}
|
|
78
31
|
|
|
@@ -82,34 +35,21 @@ _download_opencode_binary() {
|
|
|
82
35
|
|
|
83
36
|
_download_opencode_binary_impl() {
|
|
84
37
|
local latest_version
|
|
85
|
-
latest_version=$(
|
|
38
|
+
latest_version=$(github_latest_tag anomalyco/opencode)
|
|
86
39
|
if [ -z "$latest_version" ]; then
|
|
87
40
|
log_error "Failed to fetch latest OpenCode version"
|
|
88
41
|
return 1
|
|
89
42
|
fi
|
|
90
43
|
|
|
91
44
|
mkdir -p "$OPENCODE_DATA_DIR"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if ! curl -fsSL "$download_url" -o "$OPENCODE_DATA_DIR/$tarball" &>>"$LOG_FILE"; then
|
|
97
|
-
log_error "Failed to download OpenCode binary"
|
|
98
|
-
return 1
|
|
99
|
-
fi
|
|
100
|
-
|
|
101
|
-
if ! tar -zxf "$OPENCODE_DATA_DIR/$tarball" -C "$OPENCODE_DATA_DIR" &>>"$LOG_FILE"; then
|
|
102
|
-
log_error "Failed to extract OpenCode binary"
|
|
103
|
-
return 1
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
rm -f "$OPENCODE_DATA_DIR/$tarball"
|
|
45
|
+
github_download_and_extract \
|
|
46
|
+
anomalyco/opencode "$latest_version" \
|
|
47
|
+
"opencode-linux-arm64.tar.gz" "$OPENCODE_DATA_DIR" || return 1
|
|
107
48
|
|
|
108
49
|
if [ ! -f "$OPENCODE_DATA_DIR/opencode" ]; then
|
|
109
50
|
log_error "OpenCode binary not found after extraction"
|
|
110
51
|
return 1
|
|
111
52
|
fi
|
|
112
|
-
|
|
113
53
|
chmod +x "$OPENCODE_DATA_DIR/opencode"
|
|
114
54
|
return 0
|
|
115
55
|
}
|
|
@@ -119,23 +59,14 @@ _compile_opencode_helper() {
|
|
|
119
59
|
}
|
|
120
60
|
|
|
121
61
|
_compile_opencode_helper_impl() {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return 1
|
|
126
|
-
fi
|
|
127
|
-
|
|
128
|
-
if ! cc -O2 -o "$PREFIX/bin/opencode" "$HELPER_SRC" &>>"$LOG_FILE"; then
|
|
129
|
-
log_error "Failed to compile opencode helper"
|
|
130
|
-
return 1
|
|
131
|
-
fi
|
|
132
|
-
|
|
133
|
-
chmod +x "$PREFIX/bin/opencode"
|
|
62
|
+
compile_helper \
|
|
63
|
+
"$KARNEL_PATH/tools/ai/opencode/helper/opencode_helper.c" \
|
|
64
|
+
"$PREFIX/bin/opencode" || return 1
|
|
134
65
|
return 0
|
|
135
66
|
}
|
|
136
67
|
|
|
137
68
|
_install_opencode_native() {
|
|
138
|
-
|
|
69
|
+
_install_opencode_deps || return 1
|
|
139
70
|
_download_opencode_binary || return 1
|
|
140
71
|
_compile_opencode_helper || return 1
|
|
141
72
|
log_success "OpenCode installed natively"
|
|
@@ -148,48 +79,35 @@ _install_opencode_proot() {
|
|
|
148
79
|
|
|
149
80
|
_install_opencode_proot_impl() {
|
|
150
81
|
mkdir -p "$(dirname "$LOG_FILE")"
|
|
82
|
+
proot_install_ubuntu ubuntu:24.04
|
|
151
83
|
|
|
152
|
-
|
|
153
|
-
pkg install proot-distro -y &>>"$LOG_FILE"
|
|
154
|
-
fi
|
|
155
|
-
|
|
156
|
-
if [ ! -d "$(_opencode_detect_ubuntu_root)" ]; then
|
|
157
|
-
proot-distro install ubuntu:24.04 &>>"$LOG_FILE"
|
|
158
|
-
fi
|
|
159
|
-
|
|
160
|
-
_opencode_proot_ubuntu /bin/bash -c \
|
|
84
|
+
proot_ubuntu /bin/bash -c \
|
|
161
85
|
'apt-get update && apt-get upgrade -y && apt-get install -y curl ca-certificates' \
|
|
162
86
|
&>>"$LOG_FILE"
|
|
163
87
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
88
|
+
proot_ubuntu /bin/bash -c '
|
|
89
|
+
export SHELL=/bin/bash
|
|
90
|
+
export TMPDIR=/tmp
|
|
91
|
+
export HOME=/root
|
|
92
|
+
curl -fsSL https://opencode.ai/install | bash -s -- --no-modify-path
|
|
93
|
+
' &>>"$LOG_FILE"
|
|
170
94
|
|
|
171
95
|
local ubuntu_root
|
|
172
|
-
ubuntu_root="$(
|
|
173
|
-
|
|
96
|
+
ubuntu_root="$(detect_ubuntu_root)"
|
|
174
97
|
if [ -z "$ubuntu_root" ]; then
|
|
175
98
|
log_error "Ubuntu rootfs not found"
|
|
176
99
|
return 1
|
|
177
100
|
fi
|
|
178
101
|
|
|
179
102
|
local opencode_bin="$ubuntu_root/root/.opencode/bin/opencode"
|
|
180
|
-
|
|
181
103
|
if [ ! -f "$opencode_bin" ]; then
|
|
182
104
|
log_error "OpenCode binary not found after install"
|
|
183
105
|
return 1
|
|
184
106
|
fi
|
|
185
107
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
return 1
|
|
190
|
-
fi
|
|
191
|
-
sed "s|__UBUNTU_ROOTFS__|$ubuntu_root|g" "$wrapper_src" >"$PREFIX/bin/opencode"
|
|
192
|
-
chmod +x "$PREFIX/bin/opencode"
|
|
108
|
+
generate_wrapper \
|
|
109
|
+
"$KARNEL_PATH/tools/ai/opencode/bin/opencode" \
|
|
110
|
+
"$ubuntu_root" "$PREFIX/bin/opencode" || return 1
|
|
193
111
|
|
|
194
112
|
if ! grep -q '.opencode/bin' "$ubuntu_root/root/.bashrc" 2>/dev/null; then
|
|
195
113
|
printf '\n# opencode\nexport PATH=/root/.opencode/bin:$PATH\n' >>"$ubuntu_root/root/.bashrc"
|
|
@@ -205,18 +123,13 @@ install_opencode() {
|
|
|
205
123
|
fi
|
|
206
124
|
|
|
207
125
|
log_info "Select installation method for OpenCode:"
|
|
208
|
-
|
|
209
126
|
read_select "Installation method" SELECTED_METHOD \
|
|
210
127
|
"Native (recommended) - Compile with glibc support" \
|
|
211
128
|
"Proot-distro (alternative) - Ubuntu container"
|
|
212
129
|
|
|
213
130
|
case "$SELECTED_METHOD" in
|
|
214
|
-
*Native*)
|
|
215
|
-
|
|
216
|
-
;;
|
|
217
|
-
*Proot-distro*)
|
|
218
|
-
_install_opencode_proot
|
|
219
|
-
;;
|
|
131
|
+
*Native*) _install_opencode_native ;;
|
|
132
|
+
*Proot-distro*) _install_opencode_proot ;;
|
|
220
133
|
esac
|
|
221
134
|
}
|
|
222
135
|
|
|
@@ -236,13 +149,11 @@ uninstall_opencode() {
|
|
|
236
149
|
return 0
|
|
237
150
|
fi
|
|
238
151
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if [ -f "$ubuntu_bashrc" ]; then
|
|
245
|
-
sed -i '/# opencode/d; /export PATH=\/root\/.opencode\/bin/d' "$ubuntu_bashrc"
|
|
152
|
+
proot_ubuntu /bin/bash -c 'rm -rf /root/.opencode' &>>"$LOG_FILE"
|
|
153
|
+
local ubuntu_root
|
|
154
|
+
ubuntu_root="$(detect_ubuntu_root)/root/.bashrc"
|
|
155
|
+
if [ -f "$ubuntu_root" ]; then
|
|
156
|
+
sed -i '/# opencode/d; /export PATH=\/root\/.opencode\/bin/d' "$ubuntu_root"
|
|
246
157
|
fi
|
|
247
158
|
|
|
248
159
|
if rm -f "$PREFIX/bin/opencode" &>>"$LOG_FILE"; then
|
|
@@ -264,9 +175,8 @@ _do_update_opencode() {
|
|
|
264
175
|
return $?
|
|
265
176
|
fi
|
|
266
177
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
_opencode_proot_ubuntu /bin/bash -c '
|
|
178
|
+
proot_ubuntu /bin/bash -c 'rm -rf /root/.opencode' &>>"$LOG_FILE"
|
|
179
|
+
proot_ubuntu /bin/bash -c '
|
|
270
180
|
export SHELL=/bin/bash
|
|
271
181
|
export TMPDIR=/tmp
|
|
272
182
|
export HOME=/root
|
|
@@ -274,14 +184,11 @@ _do_update_opencode() {
|
|
|
274
184
|
' &>>"$LOG_FILE"
|
|
275
185
|
|
|
276
186
|
local ubuntu_root
|
|
277
|
-
ubuntu_root="$(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if [ ! -f "$opencode_bin" ]; then
|
|
187
|
+
ubuntu_root="$(detect_ubuntu_root)"
|
|
188
|
+
if [ -z "$ubuntu_root" ] || [ ! -f "$ubuntu_root/root/.opencode/bin/opencode" ]; then
|
|
281
189
|
log_error "OpenCode binary not found after update"
|
|
282
190
|
return 1
|
|
283
191
|
fi
|
|
284
|
-
|
|
285
192
|
return 0
|
|
286
193
|
}
|
|
287
194
|
|
|
@@ -240,14 +240,15 @@ int access(const char *p, int mode) {
|
|
|
240
240
|
ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
|
|
241
241
|
if (path && streq(path, "/proc/self/exe")) {
|
|
242
242
|
int len = slen(wrapper_path);
|
|
243
|
-
|
|
243
|
+
int to_copy = len < (int)bufsiz ? len : (int)bufsiz - 1;
|
|
244
|
+
if (to_copy > 0) {
|
|
244
245
|
char *d = buf;
|
|
245
246
|
const char *s = wrapper_path;
|
|
246
|
-
|
|
247
|
+
for (int i = 0; i < to_copy; i++)
|
|
247
248
|
*d++ = *s++;
|
|
248
249
|
*d = '\0';
|
|
249
250
|
}
|
|
250
|
-
return
|
|
251
|
+
return to_copy > 0 ? to_copy : 0;
|
|
251
252
|
}
|
|
252
253
|
return (ssize_t)SREADLINKAT(dirfd, path, buf, bufsiz);
|
|
253
254
|
}
|
|
@@ -270,9 +271,14 @@ ssize_t readlinkat(int dirfd, const char *path, char *buf, size_t bufsiz) {
|
|
|
270
271
|
* bionic binaries. We use --library-path/--preload for glibc binaries instead.
|
|
271
272
|
* Returns pointer to static buffer. */
|
|
272
273
|
static char **strip_glibc_env(char *const envp[]) {
|
|
273
|
-
|
|
274
|
+
int count = 0;
|
|
275
|
+
while (envp[count])
|
|
276
|
+
count++;
|
|
277
|
+
static char *clean[4096];
|
|
278
|
+
if (count > 4095)
|
|
279
|
+
count = 4095;
|
|
274
280
|
int j = 0;
|
|
275
|
-
for (int i = 0; envp[i] && j <
|
|
281
|
+
for (int i = 0; envp[i] && j < count; i++) {
|
|
276
282
|
const char *e = envp[i];
|
|
277
283
|
/* Skip LD_LIBRARY_PATH=* */
|
|
278
284
|
if (e[0] == 'L' && e[1] == 'D' && e[2] == '_' && e[3] == 'L' &&
|
|
@@ -301,7 +307,9 @@ int execve(const char *pathname, char *const argv[], char *const envp[]) {
|
|
|
301
307
|
while (argv[argc])
|
|
302
308
|
argc++;
|
|
303
309
|
|
|
304
|
-
|
|
310
|
+
if (argc + 7 > 1024)
|
|
311
|
+
goto fallback;
|
|
312
|
+
char *new_argv[1024];
|
|
305
313
|
int i = 0;
|
|
306
314
|
new_argv[i++] = (char *)pathname;
|
|
307
315
|
new_argv[i++] = "--library-path";
|
|
@@ -331,7 +339,9 @@ int execve(const char *pathname, char *const argv[], char *const envp[]) {
|
|
|
331
339
|
while (argv[argc])
|
|
332
340
|
argc++;
|
|
333
341
|
|
|
334
|
-
|
|
342
|
+
if (argc + 8 > 1024)
|
|
343
|
+
goto fallback;
|
|
344
|
+
char *new_argv[1024];
|
|
335
345
|
int i = 0;
|
|
336
346
|
new_argv[i++] = (char *)ld_path;
|
|
337
347
|
new_argv[i++] = "--library-path";
|
|
@@ -349,4 +359,15 @@ int execve(const char *pathname, char *const argv[], char *const envp[]) {
|
|
|
349
359
|
|
|
350
360
|
errno = err;
|
|
351
361
|
return -1;
|
|
362
|
+
|
|
363
|
+
fallback:
|
|
364
|
+
/* If argv was too large for our static buffer, try the original execve */
|
|
365
|
+
r = SEXECVE(pathname, argv, clean_env);
|
|
366
|
+
if (r >= 0)
|
|
367
|
+
return (int)r;
|
|
368
|
+
r = SEXECVE(pathname, argv, envp);
|
|
369
|
+
if (r >= 0)
|
|
370
|
+
return (int)r;
|
|
371
|
+
errno = (int)(-r);
|
|
372
|
+
return -1;
|
|
352
373
|
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
PLUGINS_DIR="${KARNEL_DATA}/plugins"
|
|
2
|
+
|
|
3
|
+
_plugin_dir() {
|
|
4
|
+
echo "$PLUGINS_DIR/$1"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
_plugin_manifest() {
|
|
8
|
+
echo "$(_plugin_dir "$1")/karnel-plugin.json"
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
_plugin_installed() {
|
|
12
|
+
[[ -f "$(_plugin_manifest "$1")" ]]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
_plugin_name_from_repo() {
|
|
16
|
+
local repo="$1"
|
|
17
|
+
basename "$repo" | sed 's/\.git$//'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
install_plugin() {
|
|
21
|
+
local repo="$1"
|
|
22
|
+
local name
|
|
23
|
+
name="$(_plugin_name_from_repo "$repo")"
|
|
24
|
+
|
|
25
|
+
if _plugin_installed "$name"; then
|
|
26
|
+
log_info "Plugin '$name' is already installed"
|
|
27
|
+
return 2
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
mkdir -p "$PLUGINS_DIR"
|
|
31
|
+
log_info "Installing plugin '$name' from $repo..."
|
|
32
|
+
|
|
33
|
+
if ! git clone "https://github.com/$repo.git" "$(_plugin_dir "$name")" 2>/dev/null; then
|
|
34
|
+
log_error "Failed to clone $repo"
|
|
35
|
+
return 1
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if [[ ! -f "$(_plugin_manifest "$name")" ]]; then
|
|
39
|
+
log_warn "Plugin '$name' has no karnel-plugin.json manifest"
|
|
40
|
+
log_info "Creating default manifest..."
|
|
41
|
+
cat > "$(_plugin_manifest "$name")" <<MANIFEST
|
|
42
|
+
{
|
|
43
|
+
"name": "$name",
|
|
44
|
+
"version": "1.0.0",
|
|
45
|
+
"description": "Plugin installed from $repo",
|
|
46
|
+
"commands": [],
|
|
47
|
+
"tools": []
|
|
48
|
+
}
|
|
49
|
+
MANIFEST
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
chmod +x "$(_plugin_dir "$name")/commands/"*.sh 2>/dev/null || true
|
|
53
|
+
|
|
54
|
+
log_success "Plugin '$name' installed"
|
|
55
|
+
return 0
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
uninstall_plugin() {
|
|
59
|
+
local name="$1"
|
|
60
|
+
|
|
61
|
+
if ! _plugin_installed "$name"; then
|
|
62
|
+
log_info "Plugin '$name' is not installed"
|
|
63
|
+
return 2
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
log_info "Removing plugin '$name'..."
|
|
67
|
+
rm -rf "$(_plugin_dir "$name")"
|
|
68
|
+
log_success "Plugin '$name' removed"
|
|
69
|
+
return 0
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
update_plugin() {
|
|
73
|
+
local name="$1"
|
|
74
|
+
|
|
75
|
+
if ! _plugin_installed "$name"; then
|
|
76
|
+
log_info "Plugin '$name' is not installed"
|
|
77
|
+
return 2
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
log_info "Updating plugin '$name'..."
|
|
81
|
+
if ! git -C "$(_plugin_dir "$name")" pull 2>/dev/null; then
|
|
82
|
+
log_error "Failed to update '$name'"
|
|
83
|
+
return 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
log_success "Plugin '$name' updated"
|
|
87
|
+
return 0
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
reinstall_plugin() {
|
|
91
|
+
local name="$1"
|
|
92
|
+
uninstall_plugin "$name"
|
|
93
|
+
local repo
|
|
94
|
+
repo="$(git -C "$(_plugin_dir "$name")" remote get-url origin 2>/dev/null || echo "")"
|
|
95
|
+
repo="${repo#https://github.com/}"
|
|
96
|
+
repo="${repo%.git}"
|
|
97
|
+
if [[ -n "$repo" ]]; then
|
|
98
|
+
install_plugin "$repo"
|
|
99
|
+
else
|
|
100
|
+
log_error "Cannot determine repository for '$name'"
|
|
101
|
+
return 1
|
|
102
|
+
fi
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
_list_plugins() {
|
|
106
|
+
mkdir -p "$PLUGINS_DIR"
|
|
107
|
+
local found=0
|
|
108
|
+
for dir in "$PLUGINS_DIR"/*/; do
|
|
109
|
+
[[ -d "$dir" ]] || continue
|
|
110
|
+
local name
|
|
111
|
+
name="$(basename "$dir")"
|
|
112
|
+
if [[ -f "$dir/karnel-plugin.json" ]]; then
|
|
113
|
+
local desc
|
|
114
|
+
desc="$(sed -n 's/.*"description": "\(.*\)",/\1/p' "$dir/karnel-plugin.json" 2>/dev/null || echo "No description")"
|
|
115
|
+
printf " ${D_GREEN}%-20s${NC} %s\n" "$name" "$desc"
|
|
116
|
+
found=1
|
|
117
|
+
fi
|
|
118
|
+
done
|
|
119
|
+
[[ $found -eq 0 ]] && echo " No plugins installed"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
_plugin_commands() {
|
|
123
|
+
mkdir -p "$PLUGINS_DIR"
|
|
124
|
+
for dir in "$PLUGINS_DIR"/*/; do
|
|
125
|
+
[[ -d "$dir" ]] || continue
|
|
126
|
+
local cmd_dir="$dir/commands"
|
|
127
|
+
[[ -d "$cmd_dir" ]] || continue
|
|
128
|
+
for cmd_file in "$cmd_dir"/*.sh; do
|
|
129
|
+
[[ -f "$cmd_file" ]] || continue
|
|
130
|
+
local cmd_name
|
|
131
|
+
cmd_name="$(basename "$cmd_file" .sh)"
|
|
132
|
+
echo "$cmd_file:$cmd_name"
|
|
133
|
+
done
|
|
134
|
+
done
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
_plugin_dispatch() {
|
|
138
|
+
local cmd="$1"
|
|
139
|
+
shift
|
|
140
|
+
while IFS=':' read -r cmd_file cmd_name; do
|
|
141
|
+
if [[ "$cmd_name" == "$cmd" ]]; then
|
|
142
|
+
source "$cmd_file"
|
|
143
|
+
if declare -f "${cmd_name}_main" &>/dev/null; then
|
|
144
|
+
"${cmd_name}_main" "$@"
|
|
145
|
+
return $?
|
|
146
|
+
fi
|
|
147
|
+
fi
|
|
148
|
+
done < <(_plugin_commands)
|
|
149
|
+
return 1
|
|
150
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
SECURITY_TOOLS=(
|
|
2
|
+
"nmap"
|
|
3
|
+
"hydra"
|
|
4
|
+
"nikto"
|
|
5
|
+
"sqlmap"
|
|
6
|
+
"gobuster"
|
|
7
|
+
"dirb"
|
|
8
|
+
"wpscan"
|
|
9
|
+
"john"
|
|
10
|
+
"aircrack-ng"
|
|
11
|
+
"metasploit"
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
for _tool in "${SECURITY_TOOLS[@]}"; do
|
|
15
|
+
source "$(dirname "${BASH_SOURCE[0]}")/$_tool/install.sh"
|
|
16
|
+
done
|
|
17
|
+
|
|
18
|
+
_batch_security() {
|
|
19
|
+
local action="$1"
|
|
20
|
+
local action_past="$2"
|
|
21
|
+
local -n count_var="$3"
|
|
22
|
+
for tool in "${SECURITY_TOOLS[@]}"; do
|
|
23
|
+
func_name="${action}_${tool//-/_}"
|
|
24
|
+
loading "${action_past^}ing ${tool}" "$func_name"
|
|
25
|
+
case $? in
|
|
26
|
+
0) ((count_var++)) ;;
|
|
27
|
+
2) ((skipped_count++)) ;;
|
|
28
|
+
1) ((failed_count++)) ;;
|
|
29
|
+
esac
|
|
30
|
+
done
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
install_all_security() {
|
|
34
|
+
local installed_count=0 skipped_count=0 failed_count=0
|
|
35
|
+
_batch_security "install" "install" installed_count
|
|
36
|
+
echo
|
|
37
|
+
log_success "Security: $installed_count installed, $skipped_count skipped, $failed_count failed"
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
uninstall_all_security() { _batch_security "uninstall" "uninstall" _unused; }
|
|
41
|
+
update_all_security() { _batch_security "update" "update" _unused; }
|
|
42
|
+
reinstall_all_security() { _batch_security "reinstall" "reinstall" _unused; }
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Template for security tool installers.
|
|
2
|
+
# Copy this file and replace TOOL_NAME with the actual tool name.
|
|
3
|
+
|
|
4
|
+
_TOOL="tool"
|
|
5
|
+
_TOOL_PKG="$1"
|
|
6
|
+
|
|
7
|
+
install_${_TOOL}() {
|
|
8
|
+
if command -v "$_TOOL" &>/dev/null; then
|
|
9
|
+
log_info "$_TOOL is already installed"
|
|
10
|
+
return 2
|
|
11
|
+
fi
|
|
12
|
+
log_info "Installing $_TOOL..."
|
|
13
|
+
if pkg install -y "$_TOOL_PKG" 2>/dev/null || apt install -y "$_TOOL_PKG" 2>/dev/null; then
|
|
14
|
+
log_success "$_TOOL installed"
|
|
15
|
+
return 0
|
|
16
|
+
fi
|
|
17
|
+
log_error "Failed to install $_TOOL"
|
|
18
|
+
return 1
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
uninstall_${_TOOL}() {
|
|
22
|
+
log_info "Removing $_TOOL..."
|
|
23
|
+
pkg uninstall -y "$_TOOL_PKG" 2>/dev/null || true
|
|
24
|
+
log_success "$_TOOL removed"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
update_${_TOOL}() {
|
|
28
|
+
log_info "$_TOOL updated via package manager"
|
|
29
|
+
return 2
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
reinstall_${_TOOL}() {
|
|
33
|
+
uninstall_$_TOOL
|
|
34
|
+
install_$_TOOL
|
|
35
|
+
}
|
package/karnel/utils/banner.sh
CHANGED
|
@@ -103,23 +103,37 @@ _repeat() {
|
|
|
103
103
|
# ================================================================
|
|
104
104
|
# Counters
|
|
105
105
|
# ================================================================
|
|
106
|
-
_count_ai() {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
106
|
+
_count_ai() {
|
|
107
|
+
local reg="$KARNEL_PATH/tools/ai/all.sh"
|
|
108
|
+
local c=0
|
|
109
|
+
if [[ -f "$reg" ]]; then
|
|
110
|
+
while IFS= read -r line; do
|
|
111
|
+
[[ "$line" =~ ^[[:space:]]*\"([^\"]+)\" ]] || continue
|
|
112
|
+
local entry="${BASH_REMATCH[1]}"
|
|
113
|
+
local bin="${entry##*:}"
|
|
114
|
+
command -v "$bin" &>/dev/null && ((c++))
|
|
115
|
+
done < <(grep -E '^\s+"' "$reg" 2>/dev/null || true)
|
|
116
|
+
fi
|
|
117
|
+
echo "$c"
|
|
118
|
+
}
|
|
119
|
+
_count_lang() { local c=0; for cmd in node python rustc go clang php perl bun; do command -v "$cmd" &>/dev/null && ((c++)); done; echo "$c"; }
|
|
120
|
+
_count_db() { local c=0; command -v pg_ctl &>/dev/null && ((c++)); command -v mariadb &>/dev/null && ((c++)); command -v sqlite3 &>/dev/null && ((c++)); command -v mongod &>/dev/null && ((c++)); command -v redis-cli &>/dev/null && ((c++)); echo "$c"; }
|
|
121
|
+
_count_doctor() {
|
|
122
|
+
local doc_sh="$KARNEL_PATH/cli/commands/doctor/code_langs.sh"
|
|
123
|
+
if [[ -f "$doc_sh" ]]; then
|
|
124
|
+
local count; count=$(grep -c 'LANG_TOOLS\[' "$doc_sh" 2>/dev/null || echo 0)
|
|
125
|
+
echo "$count"
|
|
126
|
+
else echo "0"; fi
|
|
117
127
|
}
|
|
118
|
-
|
|
119
|
-
if
|
|
120
|
-
local
|
|
121
|
-
[[ -
|
|
122
|
-
|
|
128
|
+
_pg_status() {
|
|
129
|
+
if command -v pg_ctl &>/dev/null; then
|
|
130
|
+
local data="$KARNEL_DATA/pg/data"
|
|
131
|
+
if [[ -d "$data" ]] && pg_ctl status -D "$data" &>/dev/null 2>&1; then
|
|
132
|
+
echo "ON"
|
|
133
|
+
else
|
|
134
|
+
echo "OFF"
|
|
135
|
+
fi
|
|
136
|
+
else echo "—"; fi
|
|
123
137
|
}
|
|
124
138
|
|
|
125
139
|
# ================================================================
|
|
@@ -236,16 +250,16 @@ _render_frame_line() {
|
|
|
236
250
|
# ================================================================
|
|
237
251
|
# Panel
|
|
238
252
|
# ================================================================
|
|
239
|
-
PANEL_HEADERS=("AI" "Lang" "DB" "
|
|
240
|
-
PANEL_ICONS=("◆" "</>" "⛁" "
|
|
253
|
+
PANEL_HEADERS=("AI" "Lang" "DB" "Doctor" "PG")
|
|
254
|
+
PANEL_ICONS=("◆" "</>" "⛁" "◈" "🐘")
|
|
241
255
|
|
|
242
256
|
_panel_value() {
|
|
243
257
|
case $1 in
|
|
244
258
|
0) echo "${KAI_VAL:-$(_count_ai)}" ;;
|
|
245
259
|
1) echo "${KLANG_VAL:-$(_count_lang)}" ;;
|
|
246
260
|
2) echo "${KDB_VAL:-$(_count_db)}" ;;
|
|
247
|
-
3) echo "${
|
|
248
|
-
4) echo "${
|
|
261
|
+
3) echo "${KDOCTOR_VAL:-$(_count_doctor)}" ;;
|
|
262
|
+
4) echo "${KPG_VAL:-$(_pg_status)}" ;;
|
|
249
263
|
esac
|
|
250
264
|
}
|
|
251
265
|
|
|
@@ -430,8 +444,8 @@ _render_animated() {
|
|
|
430
444
|
KAI_VAL=$(_count_ai)
|
|
431
445
|
KLANG_VAL=$(_count_lang)
|
|
432
446
|
KDB_VAL=$(_count_db)
|
|
433
|
-
|
|
434
|
-
|
|
447
|
+
KDOCTOR_VAL=$(_count_doctor)
|
|
448
|
+
KPG_VAL=$(_pg_status)
|
|
435
449
|
|
|
436
450
|
# Cache banner for clear() override (capture only, no terminal output)
|
|
437
451
|
_banner_output=$(_render 2>/dev/null) || true
|