karnel-termux 4.17.22 → 4.17.27
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 +3 -2
- package/install.sh +20 -5
- package/karnel/RELEASE_COMMIT +1 -1
- package/karnel/cli/commands/doctor/fixes.sh +4 -4
- package/karnel/cli/commands/doctor.sh +4 -2
- package/karnel/cli/commands/update.sh +18 -0
- package/karnel/cli/commands/upgrade.sh +9 -2
- package/karnel/modules/voice.sh +8 -5
- package/karnel/tools/ai/codebuff/install.sh +69 -9
- package/karnel/tools/ai/codex/install.sh +3 -0
- package/karnel/tools/ai/gemini-cli/install.sh +3 -0
- package/karnel/tools/ai/kimi-code/install.sh +3 -0
- package/karnel/tools/ai/minimax-cli/install.sh +3 -0
- package/karnel/tools/ai/openclaude/install.sh +3 -0
- package/karnel/tools/ai/openclaw/install.sh +3 -0
- package/karnel/tools/ai/pi/install.sh +3 -0
- package/karnel/tools/ai/qoder/install.sh +140 -29
- package/karnel/tools/ai/qwen-code/install.sh +3 -0
- package/karnel/tools/deploy/netlify/install.sh +10 -3
- package/karnel/tools/deploy/vercel/install.sh +10 -3
- package/karnel/tools/npm/all.sh +1 -23
- package/karnel/tools/npm/live-server/install.sh +2 -0
- package/karnel/tools/npm/localtunnel/install.sh +3 -1
- package/karnel/tools/npm/markserv/install.sh +2 -0
- package/karnel/tools/npm/ncu/install.sh +2 -0
- package/karnel/tools/npm/nestjs/install.sh +2 -0
- package/karnel/tools/npm/ngrok/install.sh +2 -0
- package/karnel/tools/npm/prettier/install.sh +2 -0
- package/karnel/tools/npm/psqlformat/install.sh +2 -0
- package/karnel/tools/npm/typescript/install.sh +2 -0
- package/karnel/tools/npm/vercel/install.sh +2 -0
- package/karnel/tools/utils/filecheck/filecheck.py +1 -0
- package/karnel/tools/utils/qrcode/install.sh +15 -1
- package/karnel/tools/utils/qrcode/qrcode.py +7 -28
- package/karnel/tools/utils/websites/websites.py +1 -0
- package/karnel/tools/voice/uninstall.sh +1 -0
- package/karnel/utils/downloaded-python.sh +1 -1
- package/karnel/utils/npm-shebang.sh +30 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -636,8 +636,9 @@ karnel update karnel # Update the framework
|
|
|
636
636
|
|
|
637
637
|
`karnel update` requires a target such as `karnel`, `ai`, or `security`.
|
|
638
638
|
`karnel update karnel` first runs the official curl installer, then falls back to
|
|
639
|
-
the local Git checkout
|
|
640
|
-
|
|
639
|
+
the local Git checkout if needed. Package-manager fallback is used only when the
|
|
640
|
+
active framework was installed by that package manager. The curl installer is
|
|
641
|
+
pinned to the latest GitHub release tag, and its SHA-256 checksum is verified
|
|
641
642
|
before it runs. The framework checks for a new version in the background at most
|
|
642
643
|
once every 24 hours; the check can use npm or GitHub and writes state under
|
|
643
644
|
`$KARNEL_CACHE`.
|
package/install.sh
CHANGED
|
@@ -147,7 +147,10 @@ bootstrap_dependencies() {
|
|
|
147
147
|
|
|
148
148
|
if [[ $needed_tput -eq 1 ]]; then
|
|
149
149
|
echo -e " ${P_BORDER}→${P_NC} Installing ncurses-utils..."
|
|
150
|
-
pkg install -y ncurses-utils &>/dev/null
|
|
150
|
+
if ! pkg install -y ncurses-utils &>/dev/null; then
|
|
151
|
+
log_fail "Failed to install ncurses-utils"
|
|
152
|
+
return 1
|
|
153
|
+
fi
|
|
151
154
|
echo -e " ${P_OK}✔${P_NC} ncurses installed"
|
|
152
155
|
echo
|
|
153
156
|
fi
|
|
@@ -155,7 +158,10 @@ bootstrap_dependencies() {
|
|
|
155
158
|
if [[ $needed_git -eq 1 ]]; then
|
|
156
159
|
log_info "Installing git..."
|
|
157
160
|
progress_bar 0 10
|
|
158
|
-
pkg install -y git &>/dev/null
|
|
161
|
+
if ! pkg install -y git &>/dev/null; then
|
|
162
|
+
log_fail "Failed to install git"
|
|
163
|
+
return 1
|
|
164
|
+
fi
|
|
159
165
|
progress_bar 10 10
|
|
160
166
|
echo
|
|
161
167
|
log_ok "git installed"
|
|
@@ -164,7 +170,10 @@ bootstrap_dependencies() {
|
|
|
164
170
|
if [[ $needed_glow -eq 1 ]]; then
|
|
165
171
|
log_info "Installing glow..."
|
|
166
172
|
progress_bar 0 10
|
|
167
|
-
pkg install -y glow &>/dev/null
|
|
173
|
+
if ! pkg install -y glow &>/dev/null; then
|
|
174
|
+
log_fail "Failed to install glow"
|
|
175
|
+
return 1
|
|
176
|
+
fi
|
|
168
177
|
progress_bar 10 10
|
|
169
178
|
echo
|
|
170
179
|
log_ok "glow installed"
|
|
@@ -173,7 +182,10 @@ bootstrap_dependencies() {
|
|
|
173
182
|
if [[ $needed_gh -eq 1 ]]; then
|
|
174
183
|
log_info "Installing gh (GitHub CLI)..."
|
|
175
184
|
progress_bar 0 10
|
|
176
|
-
pkg install -y gh &>/dev/null
|
|
185
|
+
if ! pkg install -y gh &>/dev/null; then
|
|
186
|
+
log_fail "Failed to install gh"
|
|
187
|
+
return 1
|
|
188
|
+
fi
|
|
177
189
|
progress_bar 10 10
|
|
178
190
|
echo
|
|
179
191
|
log_ok "gh installed"
|
|
@@ -182,7 +194,10 @@ bootstrap_dependencies() {
|
|
|
182
194
|
if [[ $needed_rg -eq 1 ]]; then
|
|
183
195
|
log_info "Installing ripgrep..."
|
|
184
196
|
progress_bar 0 10
|
|
185
|
-
pkg install -y ripgrep &>/dev/null
|
|
197
|
+
if ! pkg install -y ripgrep &>/dev/null; then
|
|
198
|
+
log_fail "Failed to install ripgrep"
|
|
199
|
+
return 1
|
|
200
|
+
fi
|
|
186
201
|
progress_bar 10 10
|
|
187
202
|
echo
|
|
188
203
|
log_ok "ripgrep installed"
|
package/karnel/RELEASE_COMMIT
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
da9b390f62c1b73f31fa5a00a458162589b09c38
|
|
@@ -342,10 +342,11 @@ _fix_script_symlinks() {
|
|
|
342
342
|
local tool_name
|
|
343
343
|
tool_name=$(basename "$tool_dir")
|
|
344
344
|
local bin_names
|
|
345
|
-
bin_names=$(grep -E '^local BIN_NAME=' "$installer" 2>/dev/null | head -1 | sed "s/.*BIN_NAME=\"\?//;s/\"\?$//")
|
|
345
|
+
bin_names=$(grep -E '^[[:space:]]*local BIN_NAME=' "$installer" 2>/dev/null | head -1 | sed "s/.*BIN_NAME=\"\?//;s/\"\?$//")
|
|
346
346
|
[[ -z "$bin_names" ]] && bin_names="$tool_name"
|
|
347
347
|
for bin_name in $bin_names; do
|
|
348
348
|
local expected="$tool_dir/$bin_name.py"
|
|
349
|
+
[[ -f "$expected" ]] || continue
|
|
349
350
|
local link="$PREFIX/bin/$bin_name"
|
|
350
351
|
if [[ -L "$link" ]]; then
|
|
351
352
|
local target
|
|
@@ -403,15 +404,14 @@ _fix_script_missing() {
|
|
|
403
404
|
local module_name
|
|
404
405
|
module_name=$(basename "$module_dir")
|
|
405
406
|
local bin_names
|
|
406
|
-
bin_names=$(grep -E '^local BIN_NAME=' "$installer" 2>/dev/null | head -1 | sed "s/.*BIN_NAME=\"\?//;s/\"\?$//")
|
|
407
|
+
bin_names=$(grep -E '^[[:space:]]*local BIN_NAME=' "$installer" 2>/dev/null | head -1 | sed "s/.*BIN_NAME=\"\?//;s/\"\?$//")
|
|
407
408
|
[[ -z "$bin_names" ]] && bin_names="$tool_name"
|
|
408
409
|
for bin_name in $bin_names; do
|
|
409
410
|
((total++))
|
|
410
411
|
if ! command -v "$bin_name" &>/dev/null; then
|
|
411
412
|
karnel install "$module_name" "--$tool_name" &>/dev/null && ((fixed++))
|
|
412
413
|
fi
|
|
413
|
-
done
|
|
414
|
-
done < <(find "$module_dir" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null || true)
|
|
414
|
+
done done < <(find "$module_dir" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null || true)
|
|
415
415
|
done < <(find "$KARNEL_PATH/tools/" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null || true)
|
|
416
416
|
[[ $fixed -gt 0 ]] && log_success "Reinstalled $fixed/$total missing tool(s)"
|
|
417
417
|
return 0
|
|
@@ -671,7 +671,7 @@ doctor_termux() {
|
|
|
671
671
|
[[ -f "$installer" ]] || continue
|
|
672
672
|
|
|
673
673
|
local bin_names
|
|
674
|
-
bin_names=$(grep -E '^local BIN_NAME=' "$installer" 2>/dev/null | head -1 | sed "s/.*BIN_NAME=\"\?//;s/\"\?$//")
|
|
674
|
+
bin_names=$(grep -E '^[[:space:]]*local BIN_NAME=' "$installer" 2>/dev/null | head -1 | sed "s/.*BIN_NAME=\"\?//;s/\"\?$//")
|
|
675
675
|
[[ -z "$bin_names" ]] && bin_names="$tool_name"
|
|
676
676
|
|
|
677
677
|
for bin_name in $bin_names; do
|
|
@@ -684,12 +684,14 @@ doctor_termux() {
|
|
|
684
684
|
if [[ "$target" == "$tool_script" ]]; then
|
|
685
685
|
log_success "$module_name/$tool_name → $bin_name (OK)"
|
|
686
686
|
((script_ok++))
|
|
687
|
+
elif [[ ! -f "$tool_script" ]]; then
|
|
688
|
+
log_info "$bin_name: managed outside Karnel python payloads (→ $target)"
|
|
687
689
|
else
|
|
688
690
|
log_warn "$bin_name: symlink target changed (→ $target, expected $tool_script)"
|
|
689
691
|
((script_warn++)); found_symlink_issues=true
|
|
690
692
|
fi
|
|
691
693
|
|
|
692
|
-
if [[ -f "$bin_path" ]] && head -1 "$bin_path" 2>/dev/null | grep -q "^#!/usr/bin/env"; then
|
|
694
|
+
if [[ -f "$tool_script" ]] && [[ -f "$bin_path" ]] && head -1 "$bin_path" 2>/dev/null | grep -q "^#!/usr/bin/env"; then
|
|
693
695
|
log_warn "$bin_name: uses #!/usr/bin/env — will fail on Termux"
|
|
694
696
|
((script_warn++)); found_shebang_issues=true
|
|
695
697
|
fi
|
|
@@ -357,8 +357,18 @@ _npm_installed_version() {
|
|
|
357
357
|
printf '%s' "${v:-unknown}"
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
+
_update_global_package_is_active() {
|
|
361
|
+
local manager="${1:-npm}" root
|
|
362
|
+
root=$("$manager" root -g 2>/dev/null) || return 1
|
|
363
|
+
[[ "$KARNEL_PATH" == "$root/karnel-termux/karnel" ]]
|
|
364
|
+
}
|
|
365
|
+
|
|
360
366
|
_update_try_npm() {
|
|
361
367
|
command -v npm &>/dev/null || return 1
|
|
368
|
+
if ! _update_global_package_is_active; then
|
|
369
|
+
log_info "Skipping npm update: the active Karnel framework is not npm-managed"
|
|
370
|
+
return 1
|
|
371
|
+
fi
|
|
362
372
|
log_info "Trying npm update..."
|
|
363
373
|
if npm update -g karnel-termux --ignore-scripts 2>/dev/null; then
|
|
364
374
|
local new_ver
|
|
@@ -372,6 +382,10 @@ _update_try_npm() {
|
|
|
372
382
|
|
|
373
383
|
_update_try_npm_install() {
|
|
374
384
|
command -v npm &>/dev/null || return 1
|
|
385
|
+
if ! _update_global_package_is_active; then
|
|
386
|
+
log_info "Skipping npm install: the active Karnel framework is not npm-managed"
|
|
387
|
+
return 1
|
|
388
|
+
fi
|
|
375
389
|
log_info "Trying npm install..."
|
|
376
390
|
if npm install -g karnel-termux@latest --ignore-scripts 2>/dev/null; then
|
|
377
391
|
local new_ver
|
|
@@ -384,6 +398,10 @@ _update_try_npm_install() {
|
|
|
384
398
|
|
|
385
399
|
_update_try_pnpm() {
|
|
386
400
|
command -v pnpm &>/dev/null || return 1
|
|
401
|
+
if ! _update_global_package_is_active pnpm; then
|
|
402
|
+
log_info "Skipping pnpm update: the active Karnel framework is not pnpm-managed"
|
|
403
|
+
return 1
|
|
404
|
+
fi
|
|
387
405
|
log_info "Trying pnpm..."
|
|
388
406
|
if pnpm add -g karnel-termux@latest 2>/dev/null; then
|
|
389
407
|
log_success "Updated via pnpm"
|
|
@@ -15,11 +15,14 @@ upgrade_main() {
|
|
|
15
15
|
return 1
|
|
16
16
|
fi
|
|
17
17
|
|
|
18
|
+
if ! _upgrade_fix_symlink; then
|
|
19
|
+
log_error "Karnel upgrade could not activate its command"
|
|
20
|
+
return 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
18
23
|
source "$KARNEL_PATH/utils/env.sh" 2>/dev/null
|
|
19
24
|
log_success "Karnel upgraded to v$KARNEL_VERSION"
|
|
20
25
|
|
|
21
|
-
_upgrade_fix_symlink
|
|
22
|
-
|
|
23
26
|
echo
|
|
24
27
|
log_info "Running cleanup..."
|
|
25
28
|
import "@/cli/commands/cleanup"
|
|
@@ -30,6 +33,10 @@ upgrade_main() {
|
|
|
30
33
|
}
|
|
31
34
|
|
|
32
35
|
_upgrade_fix_symlink() {
|
|
36
|
+
if [[ -e "$PREFIX/bin/karnel" && ! -L "$PREFIX/bin/karnel" ]]; then
|
|
37
|
+
log_error "Refusing to replace existing non-symlink: $PREFIX/bin/karnel"
|
|
38
|
+
return 1
|
|
39
|
+
fi
|
|
33
40
|
if [[ ! -L "$PREFIX/bin/karnel" ]] || [[ "$(readlink "$PREFIX/bin/karnel")" != "$KARNEL_PATH/bin/karnel" ]]; then
|
|
34
41
|
ln -sf "$KARNEL_PATH/bin/karnel" "$PREFIX/bin/karnel" 2>/dev/null
|
|
35
42
|
log_success "Symlink updated"
|
package/karnel/modules/voice.sh
CHANGED
|
@@ -4,6 +4,7 @@ import "@/utils/log"
|
|
|
4
4
|
import "@/utils/colors"
|
|
5
5
|
|
|
6
6
|
LOG_FILE="$KARNEL_CACHE/install_voice.log"
|
|
7
|
+
VOICE_MARKER="${KARNEL_DATA:-${XDG_DATA_HOME:-$HOME/.local/share}/karnel-data}/voice/.termux-api-managed"
|
|
7
8
|
|
|
8
9
|
install_voice() {
|
|
9
10
|
separator
|
|
@@ -41,8 +42,10 @@ install_voice() {
|
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
_install_voice_deps() {
|
|
44
|
-
pkg install termux-api -y &>>"$LOG_FILE"
|
|
45
|
-
|
|
45
|
+
if ! pkg install termux-api -y &>>"$LOG_FILE"; then
|
|
46
|
+
return 1
|
|
47
|
+
fi
|
|
48
|
+
mkdir -p "$(dirname "$VOICE_MARKER")" && : >"$VOICE_MARKER"
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
_install_voice_shell() {
|
|
@@ -122,7 +125,7 @@ reinstall_voice() {
|
|
|
122
125
|
}
|
|
123
126
|
|
|
124
127
|
_reinstall_voice_wrapper() {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
_uninstall_voice_wrapper || return $?
|
|
129
|
+
_install_voice_deps || return $?
|
|
130
|
+
_install_voice_shell
|
|
128
131
|
}
|
|
@@ -9,6 +9,8 @@ LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
|
9
9
|
CODEBUFF_DATA_DIR="$HOME/.local/share/karnel-data/codebuff"
|
|
10
10
|
CODEBUFF_MARKER=".karnel-managed"
|
|
11
11
|
CODEBUFF_WRAPPER_MARKER="$CODEBUFF_DATA_DIR/.karnel-wrapper"
|
|
12
|
+
CODEBUFF_PREVIOUS_DATA=""
|
|
13
|
+
CODEBUFF_STAGED_WRAPPER=""
|
|
12
14
|
|
|
13
15
|
_codebuff_detect_ubuntu_root() {
|
|
14
16
|
local root
|
|
@@ -115,14 +117,44 @@ _download_codebuff_binary_impl() {
|
|
|
115
117
|
fi
|
|
116
118
|
|
|
117
119
|
chmod +x "$staging_dir/codebuff"
|
|
118
|
-
|
|
120
|
+
if ! _activate_codebuff_payload "$staging_dir"; then
|
|
121
|
+
rm -rf "$staging_dir"
|
|
122
|
+
return 1
|
|
123
|
+
fi
|
|
119
124
|
}
|
|
120
125
|
|
|
121
|
-
|
|
122
|
-
|
|
126
|
+
_activate_codebuff_payload() {
|
|
127
|
+
local staging_dir="$1" backup=""
|
|
128
|
+
printf '%s\n' 'karnel-managed-v1' >"$staging_dir/$CODEBUFF_MARKER" || return 1
|
|
129
|
+
if [[ -e "$CODEBUFF_DATA_DIR" ]]; then
|
|
130
|
+
if [[ ! -f "$CODEBUFF_DATA_DIR/$CODEBUFF_MARKER" ]]; then
|
|
131
|
+
log_error "Refusing to replace unowned installation: $CODEBUFF_DATA_DIR"
|
|
132
|
+
return 1
|
|
133
|
+
fi
|
|
134
|
+
backup=$(mktemp -d "$(dirname "$CODEBUFF_DATA_DIR")/.codebuff-previous.XXXXXX") || return 1
|
|
135
|
+
rmdir "$backup" || return 1
|
|
136
|
+
mv "$CODEBUFF_DATA_DIR" "$backup" || return 1
|
|
137
|
+
fi
|
|
138
|
+
if ! mv "$staging_dir" "$CODEBUFF_DATA_DIR"; then
|
|
139
|
+
[[ -z "$backup" ]] || mv "$backup" "$CODEBUFF_DATA_DIR"
|
|
140
|
+
return 1
|
|
141
|
+
fi
|
|
142
|
+
if [[ -n "$backup" && -f "$backup/.karnel-wrapper" ]] &&
|
|
143
|
+
! cp "$backup/.karnel-wrapper" "$CODEBUFF_WRAPPER_MARKER"; then
|
|
144
|
+
rm -rf "$CODEBUFF_DATA_DIR"
|
|
145
|
+
mv "$backup" "$CODEBUFF_DATA_DIR"
|
|
146
|
+
return 1
|
|
147
|
+
fi
|
|
148
|
+
CODEBUFF_PREVIOUS_DATA="$backup"
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
_restore_codebuff_payload() {
|
|
152
|
+
rm -rf "$CODEBUFF_DATA_DIR"
|
|
153
|
+
[[ -z "$CODEBUFF_PREVIOUS_DATA" ]] || mv "$CODEBUFF_PREVIOUS_DATA" "$CODEBUFF_DATA_DIR"
|
|
154
|
+
CODEBUFF_PREVIOUS_DATA=""
|
|
123
155
|
}
|
|
124
156
|
|
|
125
|
-
|
|
157
|
+
_stage_codebuff_helper() {
|
|
126
158
|
local HELPER_SRC="$KARNEL_PATH/tools/ai/codebuff/helper/codebuff_helper.c"
|
|
127
159
|
if [ ! -f "$HELPER_SRC" ]; then
|
|
128
160
|
log_error "Helper source not found at $HELPER_SRC"
|
|
@@ -130,22 +162,50 @@ _compile_codebuff_helper_impl() {
|
|
|
130
162
|
fi
|
|
131
163
|
|
|
132
164
|
local staged_wrapper
|
|
165
|
+
if [[ -e "$PREFIX/bin/codebuff" || -L "$PREFIX/bin/codebuff" ]] &&
|
|
166
|
+
! installer_file_owned "$PREFIX/bin/codebuff" "$CODEBUFF_WRAPPER_MARKER"; then
|
|
167
|
+
log_error "Refusing to replace an existing Codebuff wrapper not owned by Karnel"
|
|
168
|
+
return 1
|
|
169
|
+
fi
|
|
133
170
|
staged_wrapper=$(mktemp "$PREFIX/bin/.codebuff.XXXXXX") || return 1
|
|
134
171
|
if ! cc -O2 -o "$staged_wrapper" "$HELPER_SRC" &>>"$LOG_FILE"; then
|
|
135
172
|
rm -f "$staged_wrapper"
|
|
136
173
|
log_error "Failed to compile codebuff helper"
|
|
137
174
|
return 1
|
|
138
175
|
fi
|
|
176
|
+
chmod +x "$staged_wrapper" || { rm -f "$staged_wrapper"; return 1; }
|
|
177
|
+
CODEBUFF_STAGED_WRAPPER="$staged_wrapper"
|
|
178
|
+
}
|
|
139
179
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
180
|
+
_activate_codebuff_wrapper() {
|
|
181
|
+
activate_installer_file "$CODEBUFF_STAGED_WRAPPER" "$PREFIX/bin/codebuff" "$CODEBUFF_WRAPPER_MARKER"
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
_compile_codebuff_helper() {
|
|
185
|
+
loading "Compiling helper" _stage_codebuff_helper || return 1
|
|
186
|
+
if ! _activate_codebuff_wrapper; then
|
|
187
|
+
rm -f "$CODEBUFF_STAGED_WRAPPER"
|
|
188
|
+
return 1
|
|
189
|
+
fi
|
|
190
|
+
CODEBUFF_STAGED_WRAPPER=""
|
|
143
191
|
}
|
|
144
192
|
|
|
145
193
|
_install_codebuff_native() {
|
|
194
|
+
CODEBUFF_PREVIOUS_DATA="" CODEBUFF_STAGED_WRAPPER=""
|
|
146
195
|
_codebuff_install_deps_native || return 1
|
|
147
|
-
|
|
148
|
-
|
|
196
|
+
loading "Compiling helper" _stage_codebuff_helper || return 1
|
|
197
|
+
if ! _download_codebuff_binary; then
|
|
198
|
+
rm -f "$CODEBUFF_STAGED_WRAPPER"
|
|
199
|
+
return 1
|
|
200
|
+
fi
|
|
201
|
+
if ! _activate_codebuff_wrapper; then
|
|
202
|
+
rm -f "$CODEBUFF_STAGED_WRAPPER"
|
|
203
|
+
_restore_codebuff_payload
|
|
204
|
+
return 1
|
|
205
|
+
fi
|
|
206
|
+
CODEBUFF_STAGED_WRAPPER=""
|
|
207
|
+
[[ -z "$CODEBUFF_PREVIOUS_DATA" ]] || rm -rf "$CODEBUFF_PREVIOUS_DATA"
|
|
208
|
+
CODEBUFF_PREVIOUS_DATA=""
|
|
149
209
|
log_success "Codebuff installed natively"
|
|
150
210
|
return 0
|
|
151
211
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
7
8
|
|
|
@@ -39,6 +40,7 @@ _install_codex_npm_impl() {
|
|
|
39
40
|
log_error "Failed to install Codex CLI"
|
|
40
41
|
return 1
|
|
41
42
|
fi
|
|
43
|
+
_fix_npm_shebang "codex"
|
|
42
44
|
|
|
43
45
|
return 0
|
|
44
46
|
}
|
|
@@ -90,6 +92,7 @@ _update_codex_impl() {
|
|
|
90
92
|
log_error "Failed to update Codex CLI"
|
|
91
93
|
return 1
|
|
92
94
|
fi
|
|
95
|
+
_fix_npm_shebang "codex"
|
|
93
96
|
return 0
|
|
94
97
|
}
|
|
95
98
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
7
8
|
|
|
@@ -42,6 +43,7 @@ _install_gemini_cli_npm_impl() {
|
|
|
42
43
|
log_error "Failed to install Gemini CLI"
|
|
43
44
|
return 1
|
|
44
45
|
fi
|
|
46
|
+
_fix_npm_shebang "gemini"
|
|
45
47
|
|
|
46
48
|
return 0
|
|
47
49
|
}
|
|
@@ -97,6 +99,7 @@ _update_gemini_cli_impl() {
|
|
|
97
99
|
log_error "Failed to update Gemini CLI"
|
|
98
100
|
return 1
|
|
99
101
|
fi
|
|
102
|
+
_fix_npm_shebang "gemini"
|
|
100
103
|
return 0
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
7
8
|
|
|
@@ -39,6 +40,7 @@ _install_kimi_code_npm_impl() {
|
|
|
39
40
|
log_error "Failed to install Kimi Code"
|
|
40
41
|
return 1
|
|
41
42
|
fi
|
|
43
|
+
_fix_npm_shebang "kimi"
|
|
42
44
|
|
|
43
45
|
return 0
|
|
44
46
|
}
|
|
@@ -92,6 +94,7 @@ _update_kimi_code_impl() {
|
|
|
92
94
|
log_error "Failed to update Kimi Code"
|
|
93
95
|
return 1
|
|
94
96
|
fi
|
|
97
|
+
_fix_npm_shebang "kimi"
|
|
95
98
|
return 0
|
|
96
99
|
}
|
|
97
100
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
7
8
|
|
|
@@ -39,6 +40,7 @@ _install_minimax_cli_npm_impl() {
|
|
|
39
40
|
log_error "Failed to install MiniMax CLI"
|
|
40
41
|
return 1
|
|
41
42
|
fi
|
|
43
|
+
_fix_npm_shebang "mmx"
|
|
42
44
|
|
|
43
45
|
return 0
|
|
44
46
|
}
|
|
@@ -92,6 +94,7 @@ _update_minimax_cli_impl() {
|
|
|
92
94
|
log_error "Failed to update MiniMax CLI"
|
|
93
95
|
return 1
|
|
94
96
|
fi
|
|
97
|
+
_fix_npm_shebang "mmx"
|
|
95
98
|
return 0
|
|
96
99
|
}
|
|
97
100
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
7
8
|
|
|
@@ -42,6 +43,7 @@ _install_openclaude_npm_impl() {
|
|
|
42
43
|
log_error "Failed to install OpenClaude"
|
|
43
44
|
return 1
|
|
44
45
|
fi
|
|
46
|
+
_fix_npm_shebang "openclaude"
|
|
45
47
|
|
|
46
48
|
return 0
|
|
47
49
|
}
|
|
@@ -96,6 +98,7 @@ _update_openclaude_impl() {
|
|
|
96
98
|
log_error "Failed to update OpenClaude"
|
|
97
99
|
return 1
|
|
98
100
|
fi
|
|
101
|
+
_fix_npm_shebang "openclaude"
|
|
99
102
|
return 0
|
|
100
103
|
}
|
|
101
104
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
7
8
|
|
|
@@ -47,6 +48,7 @@ _install_openclaw_npm_impl() {
|
|
|
47
48
|
log_error "Failed to install OpenClaw"
|
|
48
49
|
return 1
|
|
49
50
|
fi
|
|
51
|
+
_fix_npm_shebang "openclaw"
|
|
50
52
|
|
|
51
53
|
return 0
|
|
52
54
|
}
|
|
@@ -101,6 +103,7 @@ _update_openclaw_impl() {
|
|
|
101
103
|
log_error "Failed to update OpenClaw"
|
|
102
104
|
return 1
|
|
103
105
|
fi
|
|
106
|
+
_fix_npm_shebang "openclaw"
|
|
104
107
|
return 0
|
|
105
108
|
}
|
|
106
109
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
import "@/utils/log"
|
|
3
3
|
import "@/utils/version"
|
|
4
|
+
import "@/utils/npm-shebang"
|
|
4
5
|
|
|
5
6
|
LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
6
7
|
|
|
@@ -39,6 +40,7 @@ _install_pi_npm_impl() {
|
|
|
39
40
|
log_error "Failed to install Pi"
|
|
40
41
|
return 1
|
|
41
42
|
fi
|
|
43
|
+
_fix_npm_shebang "pi"
|
|
42
44
|
|
|
43
45
|
return 0
|
|
44
46
|
}
|
|
@@ -90,6 +92,7 @@ _update_pi_impl() {
|
|
|
90
92
|
log_error "Failed to update Pi"
|
|
91
93
|
return 1
|
|
92
94
|
fi
|
|
95
|
+
_fix_npm_shebang "pi"
|
|
93
96
|
return 0
|
|
94
97
|
}
|
|
95
98
|
|
|
@@ -11,6 +11,8 @@ QODER_MANIFEST_URL="https://qoder-ide.oss-accelerate.aliyuncs.com/qodercli/chann
|
|
|
11
11
|
QODER_MARKER=".karnel-managed"
|
|
12
12
|
QODER_WRAPPER_MARKER="$QODER_DATA_DIR/.karnel-wrapper"
|
|
13
13
|
QODER_PROOT_MARKER="$PREFIX/share/karnel-installers/qoder"
|
|
14
|
+
QODER_PREVIOUS_DATA=""
|
|
15
|
+
QODER_STAGED_WRAPPER=""
|
|
14
16
|
|
|
15
17
|
_qoder_detect_ubuntu_root() {
|
|
16
18
|
local root
|
|
@@ -153,14 +155,44 @@ _download_qoder_binary_impl() {
|
|
|
153
155
|
fi
|
|
154
156
|
|
|
155
157
|
chmod +x "$staging_dir/qodercli"
|
|
156
|
-
|
|
158
|
+
if ! _activate_qoder_payload "$staging_dir"; then
|
|
159
|
+
rm -rf "$staging_dir"
|
|
160
|
+
return 1
|
|
161
|
+
fi
|
|
157
162
|
}
|
|
158
163
|
|
|
159
|
-
|
|
160
|
-
|
|
164
|
+
_activate_qoder_payload() {
|
|
165
|
+
local staging_dir="$1" backup=""
|
|
166
|
+
printf '%s\n' 'karnel-managed-v1' >"$staging_dir/$QODER_MARKER" || return 1
|
|
167
|
+
if [[ -e "$QODER_DATA_DIR" ]]; then
|
|
168
|
+
if [[ ! -f "$QODER_DATA_DIR/$QODER_MARKER" ]]; then
|
|
169
|
+
log_error "Refusing to replace unowned installation: $QODER_DATA_DIR"
|
|
170
|
+
return 1
|
|
171
|
+
fi
|
|
172
|
+
backup=$(mktemp -d "$(dirname "$QODER_DATA_DIR")/.qoder-previous.XXXXXX") || return 1
|
|
173
|
+
rmdir "$backup" || return 1
|
|
174
|
+
mv "$QODER_DATA_DIR" "$backup" || return 1
|
|
175
|
+
fi
|
|
176
|
+
if ! mv "$staging_dir" "$QODER_DATA_DIR"; then
|
|
177
|
+
[[ -z "$backup" ]] || mv "$backup" "$QODER_DATA_DIR"
|
|
178
|
+
return 1
|
|
179
|
+
fi
|
|
180
|
+
if [[ -n "$backup" && -f "$backup/.karnel-wrapper" ]] &&
|
|
181
|
+
! cp "$backup/.karnel-wrapper" "$QODER_WRAPPER_MARKER"; then
|
|
182
|
+
rm -rf "$QODER_DATA_DIR"
|
|
183
|
+
mv "$backup" "$QODER_DATA_DIR"
|
|
184
|
+
return 1
|
|
185
|
+
fi
|
|
186
|
+
QODER_PREVIOUS_DATA="$backup"
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
_restore_qoder_payload() {
|
|
190
|
+
rm -rf "$QODER_DATA_DIR"
|
|
191
|
+
[[ -z "$QODER_PREVIOUS_DATA" ]] || mv "$QODER_PREVIOUS_DATA" "$QODER_DATA_DIR"
|
|
192
|
+
QODER_PREVIOUS_DATA=""
|
|
161
193
|
}
|
|
162
194
|
|
|
163
|
-
|
|
195
|
+
_stage_qoder_helper() {
|
|
164
196
|
local HELPER_SRC="$KARNEL_PATH/tools/ai/qoder/helper/qoder_helper.c"
|
|
165
197
|
if [ ! -f "$HELPER_SRC" ]; then
|
|
166
198
|
log_error "Helper source not found at $HELPER_SRC"
|
|
@@ -168,22 +200,50 @@ _compile_qoder_helper_impl() {
|
|
|
168
200
|
fi
|
|
169
201
|
|
|
170
202
|
local staged_wrapper
|
|
203
|
+
if [[ -e "$PREFIX/bin/qodercli" || -L "$PREFIX/bin/qodercli" ]] &&
|
|
204
|
+
! installer_file_owned "$PREFIX/bin/qodercli" "$QODER_WRAPPER_MARKER"; then
|
|
205
|
+
log_error "Refusing to replace an existing Qoder wrapper not owned by Karnel"
|
|
206
|
+
return 1
|
|
207
|
+
fi
|
|
171
208
|
staged_wrapper=$(mktemp "$PREFIX/bin/.qodercli.XXXXXX") || return 1
|
|
172
209
|
if ! cc -O2 -o "$staged_wrapper" "$HELPER_SRC" &>>"$LOG_FILE"; then
|
|
173
210
|
rm -f "$staged_wrapper"
|
|
174
211
|
log_error "Failed to compile qoder helper"
|
|
175
212
|
return 1
|
|
176
213
|
fi
|
|
214
|
+
chmod +x "$staged_wrapper" || { rm -f "$staged_wrapper"; return 1; }
|
|
215
|
+
QODER_STAGED_WRAPPER="$staged_wrapper"
|
|
216
|
+
}
|
|
177
217
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
218
|
+
_activate_qoder_wrapper() {
|
|
219
|
+
activate_installer_file "$QODER_STAGED_WRAPPER" "$PREFIX/bin/qodercli" "$QODER_WRAPPER_MARKER"
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
_compile_qoder_helper() {
|
|
223
|
+
loading "Compiling helper" _stage_qoder_helper || return 1
|
|
224
|
+
if ! _activate_qoder_wrapper; then
|
|
225
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
226
|
+
return 1
|
|
227
|
+
fi
|
|
228
|
+
QODER_STAGED_WRAPPER=""
|
|
181
229
|
}
|
|
182
230
|
|
|
183
231
|
_install_qoder_native() {
|
|
232
|
+
QODER_PREVIOUS_DATA="" QODER_STAGED_WRAPPER=""
|
|
184
233
|
_qoder_install_deps_native || return 1
|
|
185
|
-
|
|
186
|
-
|
|
234
|
+
loading "Compiling helper" _stage_qoder_helper || return 1
|
|
235
|
+
if ! _download_qoder_binary; then
|
|
236
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
237
|
+
return 1
|
|
238
|
+
fi
|
|
239
|
+
if ! _activate_qoder_wrapper; then
|
|
240
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
241
|
+
_restore_qoder_payload
|
|
242
|
+
return 1
|
|
243
|
+
fi
|
|
244
|
+
QODER_STAGED_WRAPPER=""
|
|
245
|
+
[[ -z "$QODER_PREVIOUS_DATA" ]] || rm -rf "$QODER_PREVIOUS_DATA"
|
|
246
|
+
QODER_PREVIOUS_DATA=""
|
|
187
247
|
log_success "Qoder installed natively"
|
|
188
248
|
return 0
|
|
189
249
|
}
|
|
@@ -192,6 +252,27 @@ _install_qoder_proot() {
|
|
|
192
252
|
loading "Installing Qoder (proot-distro)" _install_qoder_proot_impl
|
|
193
253
|
}
|
|
194
254
|
|
|
255
|
+
_stage_qoder_proot_wrapper() {
|
|
256
|
+
local ubuntu_root="$1" qoder_dir="$2" wrapper_src="$KARNEL_PATH/tools/ai/qoder/bin/qodercli"
|
|
257
|
+
if [[ -e "$PREFIX/bin/qodercli" || -L "$PREFIX/bin/qodercli" ]] &&
|
|
258
|
+
! installer_file_owned "$PREFIX/bin/qodercli" "$QODER_PROOT_MARKER"; then
|
|
259
|
+
log_error "Refusing to replace an existing Qoder wrapper not owned by Karnel"
|
|
260
|
+
return 1
|
|
261
|
+
fi
|
|
262
|
+
[ -f "$wrapper_src" ] || { log_error "Wrapper template not found at $wrapper_src"; return 1; }
|
|
263
|
+
QODER_STAGED_WRAPPER=$(mktemp "$PREFIX/bin/.qodercli.XXXXXX") || return 1
|
|
264
|
+
if ! sed -e "s|__UBUNTU_ROOTFS__|$ubuntu_root|g" -e "s|__QODER_DIR__|$qoder_dir|g" \
|
|
265
|
+
"$wrapper_src" >"$QODER_STAGED_WRAPPER" || ! chmod +x "$QODER_STAGED_WRAPPER"; then
|
|
266
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
267
|
+
QODER_STAGED_WRAPPER=""
|
|
268
|
+
return 1
|
|
269
|
+
fi
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
_activate_qoder_proot_wrapper() {
|
|
273
|
+
activate_installer_file "$QODER_STAGED_WRAPPER" "$PREFIX/bin/qodercli" "$QODER_PROOT_MARKER"
|
|
274
|
+
}
|
|
275
|
+
|
|
195
276
|
_install_qoder_proot_impl() {
|
|
196
277
|
case "$(uname -m)" in
|
|
197
278
|
aarch64|arm64) ;;
|
|
@@ -200,16 +281,25 @@ _install_qoder_proot_impl() {
|
|
|
200
281
|
mkdir -p "$(dirname "$LOG_FILE")"
|
|
201
282
|
|
|
202
283
|
if ! command -v proot-distro &>/dev/null; then
|
|
203
|
-
yes | pkg install proot-distro &>>"$LOG_FILE"
|
|
284
|
+
if ! yes | pkg install proot-distro &>>"$LOG_FILE"; then
|
|
285
|
+
log_error "Failed to install proot-distro"
|
|
286
|
+
return 1
|
|
287
|
+
fi
|
|
204
288
|
fi
|
|
205
289
|
|
|
206
290
|
if [ ! -d "$(_qoder_detect_ubuntu_root)" ]; then
|
|
207
|
-
proot-distro install ubuntu:24.04 &>>"$LOG_FILE"
|
|
291
|
+
if ! proot-distro install ubuntu:24.04 &>>"$LOG_FILE"; then
|
|
292
|
+
log_error "Failed to install Ubuntu Proot"
|
|
293
|
+
return 1
|
|
294
|
+
fi
|
|
208
295
|
fi
|
|
209
296
|
|
|
210
|
-
_qoder_proot_ubuntu /bin/bash -c \
|
|
297
|
+
if ! _qoder_proot_ubuntu /bin/bash -c \
|
|
211
298
|
'apt-get update && apt-get upgrade -y && apt-get install -y curl ca-certificates' \
|
|
212
|
-
&>>"$LOG_FILE"
|
|
299
|
+
&>>"$LOG_FILE"; then
|
|
300
|
+
log_error "Failed to prepare Ubuntu Proot"
|
|
301
|
+
return 1
|
|
302
|
+
fi
|
|
213
303
|
|
|
214
304
|
local download_url
|
|
215
305
|
download_url=$(_get_qoder_download_url "arm64")
|
|
@@ -230,45 +320,54 @@ _install_qoder_proot_impl() {
|
|
|
230
320
|
log_error "Refusing to replace Qoder Proot data not owned by Karnel"
|
|
231
321
|
return 1
|
|
232
322
|
fi
|
|
233
|
-
|
|
323
|
+
if ! _stage_qoder_proot_wrapper "$ubuntu_root" "$qoder_dir"; then
|
|
324
|
+
return 1
|
|
325
|
+
fi
|
|
326
|
+
mkdir -p "$qoder_dir" || { rm -f "$QODER_STAGED_WRAPPER"; return 1; }
|
|
234
327
|
|
|
235
328
|
local archive_filename
|
|
236
329
|
archive_filename=$(basename "$download_url")
|
|
237
330
|
|
|
238
331
|
if ! curl -fsSL "$download_url" -o "$qoder_dir/$archive_filename" &>>"$LOG_FILE"; then
|
|
332
|
+
rm -rf "$qoder_dir"
|
|
333
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
239
334
|
log_error "Failed to download Qoder binary"
|
|
240
335
|
return 1
|
|
241
336
|
fi
|
|
242
337
|
|
|
243
338
|
local expected actual
|
|
244
339
|
expected=$(_get_qoder_download_sha256 arm64)
|
|
245
|
-
actual=$(sha256sum "$qoder_dir/$archive_filename" 2>>"$LOG_FILE") || return 1
|
|
340
|
+
actual=$(sha256sum "$qoder_dir/$archive_filename" 2>>"$LOG_FILE") || { rm -rf "$qoder_dir" "$QODER_STAGED_WRAPPER"; return 1; }
|
|
246
341
|
if [[ ! "$expected" =~ ^[0-9a-f]{64}$ || "${actual%% *}" != "$expected" ]]; then
|
|
247
|
-
rm -
|
|
342
|
+
rm -rf "$qoder_dir"
|
|
343
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
248
344
|
log_error "Qoder archive has no valid matching SHA-256 in the official manifest"
|
|
249
345
|
return 1
|
|
250
346
|
fi
|
|
251
347
|
if ! extract_tarball "$qoder_dir/$archive_filename" "$qoder_dir"; then
|
|
348
|
+
rm -rf "$qoder_dir"
|
|
349
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
252
350
|
return 1
|
|
253
351
|
fi
|
|
254
352
|
|
|
255
353
|
if [ ! -f "$qoder_dir/qodercli" ]; then
|
|
354
|
+
rm -rf "$qoder_dir"
|
|
355
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
256
356
|
log_error "Qoder binary not found after extraction"
|
|
257
357
|
return 1
|
|
258
358
|
fi
|
|
259
359
|
|
|
260
|
-
chmod +x "$qoder_dir/qodercli"
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
360
|
+
if ! chmod +x "$qoder_dir/qodercli" || ! printf '%s\n' 'karnel-managed-v1' >"$qoder_dir/.karnel-managed"; then
|
|
361
|
+
rm -rf "$qoder_dir"
|
|
362
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
363
|
+
return 1
|
|
364
|
+
fi
|
|
365
|
+
if ! _activate_qoder_proot_wrapper; then
|
|
366
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
367
|
+
rm -rf "$qoder_dir"
|
|
266
368
|
return 1
|
|
267
369
|
fi
|
|
268
|
-
|
|
269
|
-
"$wrapper_src" >"$PREFIX/bin/qodercli"
|
|
270
|
-
chmod +x "$PREFIX/bin/qodercli"
|
|
271
|
-
record_managed_file "$PREFIX/bin/qodercli" "$QODER_PROOT_MARKER" || return 1
|
|
370
|
+
QODER_STAGED_WRAPPER=""
|
|
272
371
|
|
|
273
372
|
return 0
|
|
274
373
|
}
|
|
@@ -409,14 +508,26 @@ _update_qoder_proot_impl() {
|
|
|
409
508
|
return 1
|
|
410
509
|
fi
|
|
411
510
|
|
|
412
|
-
chmod +x "$staging_dir/qodercli"
|
|
413
|
-
|
|
414
|
-
|
|
511
|
+
if ! chmod +x "$staging_dir/qodercli" || ! printf '%s\n' 'karnel-managed-v1' >"$staging_dir/.karnel-managed" ||
|
|
512
|
+
! _stage_qoder_proot_wrapper "$ubuntu_root" "$qoder_dir"; then
|
|
513
|
+
rm -rf "$staging_dir"
|
|
514
|
+
return 1
|
|
515
|
+
fi
|
|
516
|
+
old_dir=$(mktemp -d "$(dirname "$qoder_dir")/.qoder-previous.XXXXXX") || { rm -f "$QODER_STAGED_WRAPPER"; return 1; }
|
|
517
|
+
rmdir "$old_dir" || { rm -f "$QODER_STAGED_WRAPPER"; return 1; }
|
|
415
518
|
if ! mv "$qoder_dir" "$old_dir" || ! mv "$staging_dir" "$qoder_dir"; then
|
|
416
519
|
[[ ! -d "$old_dir" ]] || mv "$old_dir" "$qoder_dir"
|
|
417
520
|
rm -rf "$staging_dir"
|
|
521
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
522
|
+
return 1
|
|
523
|
+
fi
|
|
524
|
+
if ! _activate_qoder_proot_wrapper; then
|
|
525
|
+
rm -f "$QODER_STAGED_WRAPPER"
|
|
526
|
+
rm -rf "$qoder_dir"
|
|
527
|
+
mv "$old_dir" "$qoder_dir"
|
|
418
528
|
return 1
|
|
419
529
|
fi
|
|
530
|
+
QODER_STAGED_WRAPPER=""
|
|
420
531
|
rm -rf "$old_dir"
|
|
421
532
|
|
|
422
533
|
log_success "Qoder (proot-distro) updated"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_ai.log"
|
|
7
8
|
|
|
@@ -42,6 +43,7 @@ _install_qwen_code_npm_impl() {
|
|
|
42
43
|
log_error "Failed to install Qwen Code"
|
|
43
44
|
return 1
|
|
44
45
|
fi
|
|
46
|
+
_fix_npm_shebang "qwen"
|
|
45
47
|
|
|
46
48
|
return 0
|
|
47
49
|
}
|
|
@@ -97,6 +99,7 @@ _update_qwen_code_impl() {
|
|
|
97
99
|
log_error "Failed to update Qwen Code"
|
|
98
100
|
return 1
|
|
99
101
|
fi
|
|
102
|
+
_fix_npm_shebang "qwen"
|
|
100
103
|
return 0
|
|
101
104
|
}
|
|
102
105
|
|
|
@@ -9,7 +9,9 @@ NETLIFY_VERSION="27.1.1"
|
|
|
9
9
|
NETLIFY_MARKER="$PREFIX/share/karnel-installers/netlify"
|
|
10
10
|
|
|
11
11
|
_netlify_is_owned() {
|
|
12
|
-
|
|
12
|
+
local binary
|
|
13
|
+
binary=$(command -v netlify) || return 1
|
|
14
|
+
managed_file_matches "$binary" "$NETLIFY_MARKER"
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
_netlify_node_supported() {
|
|
@@ -43,12 +45,17 @@ install_netlify() {
|
|
|
43
45
|
log_error "Failed to install Netlify CLI (see $LOG_FILE)"
|
|
44
46
|
return 1
|
|
45
47
|
fi
|
|
46
|
-
|
|
48
|
+
local binary
|
|
49
|
+
binary=$(command -v netlify) || { log_error "Netlify CLI was not found after installation"; return 1; }
|
|
50
|
+
command -v termux-fix-shebang &>/dev/null && termux-fix-shebang "$binary" &>/dev/null
|
|
47
51
|
if ! netlify --version &>/dev/null; then
|
|
48
52
|
log_error "Netlify CLI did not start after installation"
|
|
49
53
|
return 1
|
|
50
54
|
fi
|
|
51
|
-
|
|
55
|
+
if ! record_managed_file "$binary" "$NETLIFY_MARKER"; then
|
|
56
|
+
log_error "Failed to record Netlify CLI ownership"
|
|
57
|
+
return 1
|
|
58
|
+
fi
|
|
52
59
|
log_success "Netlify CLI installed"
|
|
53
60
|
}
|
|
54
61
|
|
|
@@ -8,7 +8,9 @@ LOG_FILE="${LOG_FILE:-${KARNEL_CACHE:-$HOME/.cache/karnel}/install_deploy.log}"
|
|
|
8
8
|
VERCEL_MARKER="$PREFIX/share/karnel-installers/vercel"
|
|
9
9
|
|
|
10
10
|
_vercel_is_owned() {
|
|
11
|
-
|
|
11
|
+
local binary
|
|
12
|
+
binary=$(command -v vercel) || return 1
|
|
13
|
+
managed_file_matches "$binary" "$VERCEL_MARKER"
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
install_vercel() {
|
|
@@ -29,8 +31,13 @@ install_vercel() {
|
|
|
29
31
|
log_error "Failed to install Vercel CLI (see $LOG_FILE)"
|
|
30
32
|
return 1
|
|
31
33
|
fi
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
local binary
|
|
35
|
+
binary=$(command -v vercel) || { log_error "Vercel CLI was not found after installation"; return 1; }
|
|
36
|
+
command -v termux-fix-shebang &>/dev/null && termux-fix-shebang "$binary" &>/dev/null
|
|
37
|
+
if ! record_managed_file "$binary" "$VERCEL_MARKER"; then
|
|
38
|
+
log_error "Failed to record Vercel CLI ownership"
|
|
39
|
+
return 1
|
|
40
|
+
fi
|
|
34
41
|
log_success "Vercel CLI installed"
|
|
35
42
|
}
|
|
36
43
|
|
package/karnel/tools/npm/all.sh
CHANGED
|
@@ -26,29 +26,7 @@ done
|
|
|
26
26
|
unset _tool
|
|
27
27
|
_register_safe_reinstall_handlers npm "${NODE_PACKAGES[@]}"
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
local bin_name="$1"
|
|
31
|
-
local bin_path="$PREFIX/bin/$bin_name"
|
|
32
|
-
[ ! -f "$bin_path" ] && [ ! -L "$bin_path" ] && return 0
|
|
33
|
-
|
|
34
|
-
local real_path
|
|
35
|
-
real_path=$(readlink -f "$bin_path" 2>/dev/null || echo "$bin_path")
|
|
36
|
-
[ ! -f "$real_path" ] && return 0
|
|
37
|
-
|
|
38
|
-
local shebang
|
|
39
|
-
shebang=$(head -1 "$real_path")
|
|
40
|
-
|
|
41
|
-
case "$shebang" in
|
|
42
|
-
"#!/usr/bin/env node"|"#!/data/data/com.termux/files/usr/bin/env node")
|
|
43
|
-
sed -i "1s|.*|#!$PREFIX/bin/node|" "$real_path"
|
|
44
|
-
log_info "Fixed shebang for $bin_name: $shebang → $PREFIX/bin/node"
|
|
45
|
-
;;
|
|
46
|
-
"#!/usr/bin/env bash"|"#!/data/data/com.termux/files/usr/bin/env bash")
|
|
47
|
-
sed -i "1s|.*|#!$PREFIX/bin/bash|" "$real_path"
|
|
48
|
-
log_info "Fixed shebang for $bin_name: $shebang → $PREFIX/bin/bash"
|
|
49
|
-
;;
|
|
50
|
-
esac
|
|
51
|
-
}
|
|
29
|
+
import "@/utils/npm-shebang"
|
|
52
30
|
|
|
53
31
|
_batch_npm() {
|
|
54
32
|
local action="$1"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -81,6 +82,7 @@ _update_live_server_npm_impl() {
|
|
|
81
82
|
log_error "Failed to update Live Server"
|
|
82
83
|
return 1
|
|
83
84
|
fi
|
|
85
|
+
_fix_npm_shebang "live-server"
|
|
84
86
|
return 0
|
|
85
87
|
}
|
|
86
88
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -42,9 +43,9 @@ _install_localtunnel_npm_impl() {
|
|
|
42
43
|
log_error "Failed to install Localtunnel"
|
|
43
44
|
return 1
|
|
44
45
|
fi
|
|
46
|
+
_fix_npm_shebang "lt"
|
|
45
47
|
log_info "Applying localtunnel fix for Android..."
|
|
46
48
|
_localtunnel_fix_openurl &>>"$LOG_FILE"
|
|
47
|
-
_fix_npm_shebang "lt"
|
|
48
49
|
return 0
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -97,6 +98,7 @@ _update_localtunnel_npm_impl() {
|
|
|
97
98
|
log_error "Failed to update Localtunnel"
|
|
98
99
|
return 1
|
|
99
100
|
fi
|
|
101
|
+
_fix_npm_shebang "lt"
|
|
100
102
|
return 0
|
|
101
103
|
}
|
|
102
104
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -80,6 +81,7 @@ _update_markserv_npm_impl() {
|
|
|
80
81
|
log_error "Failed to update Markserv"
|
|
81
82
|
return 1
|
|
82
83
|
fi
|
|
84
|
+
_fix_npm_shebang "markserv"
|
|
83
85
|
return 0
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -80,6 +81,7 @@ _update_ncu_npm_impl() {
|
|
|
80
81
|
log_error "Failed to update NPM Check Updates"
|
|
81
82
|
return 1
|
|
82
83
|
fi
|
|
84
|
+
_fix_npm_shebang "ncu"
|
|
83
85
|
return 0
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -80,6 +81,7 @@ _update_nestjs_npm_impl() {
|
|
|
80
81
|
log_error "Failed to update NestJS CLI"
|
|
81
82
|
return 1
|
|
82
83
|
fi
|
|
84
|
+
_fix_npm_shebang "nest"
|
|
83
85
|
return 0
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -80,6 +81,7 @@ _update_ngrok_npm_impl() {
|
|
|
80
81
|
log_error "Failed to update Ngrok"
|
|
81
82
|
return 1
|
|
82
83
|
fi
|
|
84
|
+
_fix_npm_shebang "ngrok"
|
|
83
85
|
return 0
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -80,6 +81,7 @@ _update_prettier_npm_impl() {
|
|
|
80
81
|
log_error "Failed to update Prettier"
|
|
81
82
|
return 1
|
|
82
83
|
fi
|
|
84
|
+
_fix_npm_shebang "prettier"
|
|
83
85
|
return 0
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -80,6 +81,7 @@ _update_psqlformat_npm_impl() {
|
|
|
80
81
|
log_error "Failed to update PSQL Format"
|
|
81
82
|
return 1
|
|
82
83
|
fi
|
|
84
|
+
_fix_npm_shebang "psqlformat"
|
|
83
85
|
return 0
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -80,6 +81,7 @@ _update_typescript_npm_impl() {
|
|
|
80
81
|
log_error "Failed to update TypeScript"
|
|
81
82
|
return 1
|
|
82
83
|
fi
|
|
84
|
+
_fix_npm_shebang "tsc"
|
|
83
85
|
return 0
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/version"
|
|
5
|
+
import "@/utils/npm-shebang"
|
|
5
6
|
|
|
6
7
|
LOG_FILE="$KARNEL_CACHE/install_npm.log"
|
|
7
8
|
|
|
@@ -80,6 +81,7 @@ _update_vercel_npm_impl() {
|
|
|
80
81
|
log_error "Failed to update Vercel CLI"
|
|
81
82
|
return 1
|
|
82
83
|
fi
|
|
84
|
+
_fix_npm_shebang "vercel"
|
|
83
85
|
return 0
|
|
84
86
|
}
|
|
85
87
|
|
|
@@ -7,12 +7,25 @@ import "@/utils/downloaded-python"
|
|
|
7
7
|
LOG_FILE="$KARNEL_CACHE/install_dev.log"
|
|
8
8
|
DOWNLOAD_URL="https://raw.githubusercontent.com/dedsec1121fk/DedSec/87d69293f4b89b8ab114fa644074629e86313182/Scripts/Network%20Tools/QR%20Code%20Generator.py"
|
|
9
9
|
|
|
10
|
+
_qrcode_dependencies() {
|
|
11
|
+
if ! command -v python3 &>/dev/null && ! pkg install python -y &>>"$LOG_FILE"; then
|
|
12
|
+
return 1
|
|
13
|
+
fi
|
|
14
|
+
if ! python3 -c 'import PIL' &>/dev/null && ! pkg install python-pillow -y &>>"$LOG_FILE"; then
|
|
15
|
+
return 1
|
|
16
|
+
fi
|
|
17
|
+
if ! python3 -c 'import qrcode' &>/dev/null && ! python3 -m pip install --no-deps qrcode &>>"$LOG_FILE"; then
|
|
18
|
+
return 1
|
|
19
|
+
fi
|
|
20
|
+
python3 -c 'import qrcode, PIL' &>/dev/null
|
|
21
|
+
}
|
|
22
|
+
|
|
10
23
|
install_qrcode() {
|
|
11
24
|
local TOOL_DIR="$KARNEL_DATA/utils/qrcode"
|
|
12
25
|
local BIN_NAME="qrcode"
|
|
13
26
|
log_info "Installing QR Code Generator..."
|
|
14
27
|
mkdir -p "$(dirname "$LOG_FILE")" "$TOOL_DIR"
|
|
15
|
-
|
|
28
|
+
_qrcode_dependencies || { log_error "Failed to install QR Code Generator dependencies"; return 1; }
|
|
16
29
|
_downloaded_python_install "$BIN_NAME" "$TOOL_DIR" "$DOWNLOAD_URL" || return $?
|
|
17
30
|
log_success "QR Code Generator installed"
|
|
18
31
|
return 0
|
|
@@ -31,6 +44,7 @@ update_qrcode() {
|
|
|
31
44
|
local TOOL_DIR="$KARNEL_DATA/utils/qrcode"
|
|
32
45
|
local BIN_NAME="qrcode"
|
|
33
46
|
log_info "Updating QR Code Generator..."
|
|
47
|
+
_qrcode_dependencies || { log_error "Failed to install QR Code Generator dependencies"; return 1; }
|
|
34
48
|
_downloaded_python_update "$BIN_NAME" "$TOOL_DIR" "$DOWNLOAD_URL" || return 1
|
|
35
49
|
log_success "QR Code Generator updated"
|
|
36
50
|
return 0
|
|
@@ -1,35 +1,14 @@
|
|
|
1
1
|
#!/data/data/com.termux/files/usr/bin/python3
|
|
2
|
+
import os
|
|
2
3
|
import re
|
|
3
|
-
import subprocess
|
|
4
4
|
import sys
|
|
5
5
|
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
The 'qrcode[pil]' installs both qrcode and Pillow (PIL) for image generation.
|
|
11
|
-
"""
|
|
12
|
-
try:
|
|
13
|
-
__import__(package)
|
|
14
|
-
print(f"✅ Required package '{package}' is already installed.")
|
|
15
|
-
except ImportError:
|
|
16
|
-
print(f"📦 Package '{package}' not found. Installing now...")
|
|
17
|
-
try:
|
|
18
|
-
if package == 'qrcode':
|
|
19
|
-
# Install qrcode with pil dependency for image saving
|
|
20
|
-
subprocess.check_call([sys.executable, "-m", "pip", "install", "qrcode[pil]"])
|
|
21
|
-
else:
|
|
22
|
-
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
|
|
23
|
-
|
|
24
|
-
__import__(package)
|
|
25
|
-
print(f"✅ Successfully installed '{package}'.")
|
|
26
|
-
except subprocess.CalledProcessError as e:
|
|
27
|
-
print(f"❌ Failed to install '{package}'. Error: {e}")
|
|
28
|
-
print("Please ensure 'pip' is installed and working in Termux.")
|
|
29
|
-
sys.exit(1)
|
|
6
|
+
# The launcher is named qrcode.py, so remove its directory before importing
|
|
7
|
+
# the third-party qrcode package to avoid importing this file recursively.
|
|
8
|
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
9
|
+
sys.path = [path for path in sys.path if path not in ("", SCRIPT_DIR)]
|
|
30
10
|
|
|
31
|
-
|
|
32
|
-
import qrcode
|
|
11
|
+
import qrcode
|
|
33
12
|
|
|
34
13
|
# ----------------------------------------------------------------------
|
|
35
14
|
# --- Main Generator Function (Updated Path) ---
|
|
@@ -86,4 +65,4 @@ def generate_qr_for_link():
|
|
|
86
65
|
print(f"\n❌ Error saving file: {e}")
|
|
87
66
|
|
|
88
67
|
if __name__ == "__main__":
|
|
89
|
-
generate_qr_for_link()
|
|
68
|
+
generate_qr_for_link()
|
|
@@ -40,7 +40,7 @@ _downloaded_python_install() {
|
|
|
40
40
|
curl -fsSL "$download_url" -o "$staged_payload" || commit_failed=1
|
|
41
41
|
fi
|
|
42
42
|
if (( commit_failed != 0 )) || ! sed -i "1s|.*|#!$python3_path|" "$staged_payload" ||
|
|
43
|
-
! chmod
|
|
43
|
+
! chmod 755 "$staged_payload" || ! sha256sum "$staged_payload" >"$staged_marker" ||
|
|
44
44
|
! ln -s "$payload" "$staged_link"; then
|
|
45
45
|
rm -rf "$tool_staging" "$link_staging"
|
|
46
46
|
return 1
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Shared npm shebang repair for Termux.
|
|
4
|
+
# Rewrites `#!/usr/bin/env <interp>` shebangs of npm-installed bins to the
|
|
5
|
+
# absolute Termux interpreter path. Safe to call on any bin name.
|
|
6
|
+
|
|
7
|
+
_fix_npm_shebang() {
|
|
8
|
+
local bin_name="$1"
|
|
9
|
+
local bin_path="$PREFIX/bin/$bin_name"
|
|
10
|
+
[ ! -f "$bin_path" ] && [ ! -L "$bin_path" ] && return 0
|
|
11
|
+
|
|
12
|
+
local real_path
|
|
13
|
+
real_path=$(readlink -f "$bin_path" 2>/dev/null || echo "$bin_path")
|
|
14
|
+
[ ! -f "$real_path" ] && return 0
|
|
15
|
+
|
|
16
|
+
local shebang
|
|
17
|
+
shebang=$(head -1 "$real_path")
|
|
18
|
+
|
|
19
|
+
case "$shebang" in
|
|
20
|
+
"#!/usr/bin/env node"|"#!/data/data/com.termux/files/usr/bin/env node"|"#!$PREFIX/bin/env node")
|
|
21
|
+
sed -i "1s|.*|#!$PREFIX/bin/node|" "$real_path" || return 1
|
|
22
|
+
log_info "Fixed shebang for $bin_name: $shebang → $PREFIX/bin/node"
|
|
23
|
+
;;
|
|
24
|
+
"#!/usr/bin/env bash"|"#!/data/data/com.termux/files/usr/bin/env bash"|"#!$PREFIX/bin/env bash")
|
|
25
|
+
sed -i "1s|.*|#!$PREFIX/bin/bash|" "$real_path" || return 1
|
|
26
|
+
log_info "Fixed shebang for $bin_name: $shebang → $PREFIX/bin/bash"
|
|
27
|
+
;;
|
|
28
|
+
esac
|
|
29
|
+
return 0
|
|
30
|
+
}
|
package/package.json
CHANGED