karnel-termux 4.13.7 → 4.13.8

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 CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  <p align="center">
10
10
  <a href="https://github.com/israelmarques1024-dotcom/karnel-termux">
11
- <img src="https://img.shields.io/badge/version-4.13.7-0078D4?style=for-the-badge" alt="Version">
11
+ <img src="https://img.shields.io/badge/version-4.13.8-0078D4?style=for-the-badge" alt="Version">
12
12
  </a>
13
13
  <a href="https://www.npmjs.com/package/karnel-termux">
14
14
  <img src="https://img.shields.io/npm/v/karnel-termux?style=for-the-badge&logo=npm&color=cb3837" alt="npm">
@@ -33,11 +33,11 @@
33
33
 
34
34
  Created by **Israel Marques**.
35
35
 
36
- - **39 AI agents** for coding — Claude, Gemini, OpenCode, Qoder, Ollama, Goose, Factory Droid, Cline, Puter, OmniRoute and more
36
+ - **41 AI agents** for coding — Claude, Gemini, OpenCode, KeelCode, Qoder, Ollama, Goose, Factory Droid, Cline, Puter, OmniRoute and more
37
37
  - **8 languages** — Node.js, Python, Go, Rust, C/C++, PHP, Perl, Bun
38
38
  - **5 databases** — PostgreSQL, MariaDB, SQLite, MongoDB, Redis
39
39
  - **22 dev tools** — gh, curl, fzf, bat, lsd, jq, tmux, openssh, snyk and more
40
- - **11 utility scripts** — fconv, notes, treex, qrcode, zork and more
40
+ - **12 utility tools** — fconv, notes, treex, qrcode, SuperFile, zork and more
41
41
  - **2 network tools** — dark, dedsec-network
42
42
  - **4 deploy CLIs** — Vercel, Railway, Netlify, Supabase
43
43
  - **Responsible OSINT** — Robin v2.8 through Tor with a loopback-only web UI
@@ -114,7 +114,7 @@ karnel
114
114
  |--------|-------------|--------------|
115
115
  | `lang` | Node.js, Python, Go, Rust, C/C++, PHP, Perl, Bun | `karnel install lang` |
116
116
  | `db` | PostgreSQL, MariaDB, SQLite, MongoDB, Redis | `karnel install db` |
117
- | `ai` | 39 AI agents for coding | `karnel install ai` |
117
+ | `ai` | 41 AI agents for coding, including KeelCode | `karnel install ai` |
118
118
  | `editor` | code-server (VS Code in browser), Neovim, NvChad | `karnel install editor` |
119
119
  | `dev` | gh, curl, fzf, bat, lsd, jq and more | `karnel install dev` |
120
120
  | `npm` | TypeScript, NestJS CLI, Prettier and more | `karnel install npm` |
@@ -124,7 +124,7 @@ karnel
124
124
  | `deploy` | Vercel, Railway, Netlify, Supabase | `karnel install deploy` |
125
125
  | `games` | Buzz, CTF God, Detective, Tamagotchi and more | `karnel install games` |
126
126
  | `network` | Dark Web OSINT, DedSec Network Toolkit | `karnel install network` |
127
- | `utils` | fconv, notes, treex, passman, applaunch, qrcode, zork and more | `karnel install utils` |
127
+ | `utils` | fconv, notes, treex, SuperFile, passman, applaunch, qrcode, zork and more | `karnel install utils` |
128
128
  | `osint` | Robin v2.8, Tor, Streamlit, and LLM providers | `karnel install osint` |
129
129
  | `voice` | Speech-to-agent through Termux:API | `karnel install voice` |
130
130
  | `plugin` | Built-in plugin manager — reviewed registry and local plugins | `karnel plugin search` |
@@ -132,6 +132,20 @@ karnel
132
132
 
133
133
  ---
134
134
 
135
+ ### KeelCode and SuperFile
136
+
137
+ ```bash
138
+ # Install the KeelCode coding agent
139
+ karnel install ai --keelcode
140
+
141
+ # Install the SuperFile terminal file manager
142
+ karnel install utils --superfile
143
+ ```
144
+
145
+ Both tools support `update`, `reinstall`, and `uninstall` with the same module and flag.
146
+
147
+ ---
148
+
135
149
  ## Plugin System
136
150
 
137
151
  Discover and install reviewed plugins from the official registry:
package/install.sh CHANGED
@@ -13,6 +13,7 @@ readonly P_NC='\e[0m'
13
13
 
14
14
  REPO="https://github.com/israelmarques1024-dotcom/karnel-termux"
15
15
  BRANCH="main"
16
+ RELEASE_REF=""
16
17
  KARNEL_DATA="${XDG_DATA_HOME:-$HOME/.local/share}/karnel-data"
17
18
  KARNEL_REPO="${XDG_DATA_HOME:-$HOME/.local/share}/karnel"
18
19
  KARNEL_CACHE="${XDG_CACHE_HOME:-$HOME/.cache}/karnel"
@@ -198,14 +199,26 @@ clone_repo() {
198
199
  fi
199
200
 
200
201
  if [[ $is_dev_install -eq 1 ]]; then
202
+ if [[ -n "$RELEASE_REF" ]]; then
203
+ log_fail "A release ref cannot be installed from a development checkout"
204
+ return 1
205
+ fi
201
206
  KARNEL_REPO="$script_dir"
202
207
  log_info "Developer installation detected"
203
208
  log_ok "Using local repository"
204
209
  elif [[ -d "$KARNEL_REPO/.git" ]]; then
205
210
  progress_bar 3 10
206
- if ! git -C "$KARNEL_REPO" pull origin "$BRANCH" &>/dev/null; then
207
- log_fail "Failed to update existing repository"
208
- return 1
211
+ if [[ -n "$RELEASE_REF" ]]; then
212
+ if ! git -C "$KARNEL_REPO" fetch --depth=1 origin "refs/tags/$BRANCH" &>/dev/null ||
213
+ ! git -C "$KARNEL_REPO" checkout --detach FETCH_HEAD &>/dev/null; then
214
+ log_fail "Failed to update existing repository"
215
+ return 1
216
+ fi
217
+ else
218
+ if ! git -C "$KARNEL_REPO" pull origin "$BRANCH" &>/dev/null; then
219
+ log_fail "Failed to update existing repository"
220
+ return 1
221
+ fi
209
222
  fi
210
223
  progress_bar 10 10
211
224
  echo
@@ -303,6 +316,18 @@ show_final_message() {
303
316
  }
304
317
 
305
318
  main() {
319
+ if [[ $# -eq 2 && "$1" == "--ref" ]]; then
320
+ if [[ ! "$2" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
321
+ echo -e "\n ${P_FAIL}✖${P_NC} Invalid release ref: $2" >&2
322
+ return 1
323
+ fi
324
+ BRANCH="$2"
325
+ RELEASE_REF="$2"
326
+ elif [[ $# -ne 0 ]]; then
327
+ echo -e "\n ${P_FAIL}✖${P_NC} Usage: install.sh [--ref vX.Y.Z]" >&2
328
+ return 1
329
+ fi
330
+
306
331
  if [[ -z "${PREFIX:-}" ]]; then
307
332
  echo -e "\n ${P_FAIL}✖${P_NC} PREFIX is not set. Are you running in Termux?"
308
333
  echo -e " ${P_DIM}This installer requires Termux environment.${P_NC}"
@@ -319,4 +344,6 @@ main() {
319
344
  show_final_message
320
345
  }
321
346
 
322
- main
347
+ if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
348
+ main "$@"
349
+ fi
@@ -179,6 +179,7 @@ _install_specific_tools() {
179
179
  local module="$1"
180
180
  shift
181
181
  local -a tools=("$@")
182
+ local failed_count=0
182
183
 
183
184
  case "$module" in
184
185
  ai)
@@ -232,7 +233,7 @@ _install_specific_tools() {
232
233
  ((failed_count++))
233
234
  fi
234
235
  ;;
235
- 1)
236
+ *)
236
237
  ((failed_count++))
237
238
  ;;
238
239
  2)
@@ -288,6 +289,7 @@ _install_specific_tools() {
288
289
  ;;
289
290
  *)
290
291
  log_warn "Unknown database: --$tool"
292
+ ((failed_count++))
291
293
  ;;
292
294
  esac
293
295
  done
@@ -402,6 +404,7 @@ _install_specific_tools() {
402
404
  ;;
403
405
  *)
404
406
  log_warn "Unknown tool: --$tool"
407
+ ((failed_count++))
405
408
  ;;
406
409
  esac
407
410
  done
@@ -452,6 +455,7 @@ _install_specific_tools() {
452
455
  ;;
453
456
  *)
454
457
  log_warn "Unknown game: --$tool"
458
+ ((failed_count++))
455
459
  ;;
456
460
  esac
457
461
  done
@@ -522,6 +526,7 @@ _install_specific_tools() {
522
526
  ;;
523
527
  *)
524
528
  log_warn "Unknown node module: --$tool"
529
+ ((failed_count++))
525
530
  ;;
526
531
  esac
527
532
  done
@@ -580,6 +585,7 @@ _install_specific_tools() {
580
585
  ;;
581
586
  *)
582
587
  log_warn "Unknown language: --$tool"
588
+ ((failed_count++))
583
589
  ;;
584
590
  esac
585
591
  done
@@ -646,6 +652,7 @@ _install_specific_tools() {
646
652
  ;;
647
653
  *)
648
654
  log_warn "Unknown plugin: --$tool"
655
+ ((failed_count++))
649
656
  ;;
650
657
  esac
651
658
  done
@@ -684,6 +691,7 @@ _install_specific_tools() {
684
691
  ;;
685
692
  *)
686
693
  log_warn "Unknown editor component: --$tool"
694
+ ((failed_count++))
687
695
  ;;
688
696
  esac
689
697
  done
@@ -726,6 +734,7 @@ _install_specific_tools() {
726
734
  ;;
727
735
  *)
728
736
  log_warn "Unknown UI component: --$tool"
737
+ ((failed_count++))
729
738
  ;;
730
739
  esac
731
740
  done
@@ -756,6 +765,7 @@ _install_specific_tools() {
756
765
  ;;
757
766
  *)
758
767
  log_warn "Unknown automation tool: --$tool"
768
+ ((failed_count++))
759
769
  ;;
760
770
  esac
761
771
  done
@@ -798,6 +808,7 @@ _install_specific_tools() {
798
808
  ;;
799
809
  *)
800
810
  log_warn "Unknown deploy tool: --$tool"
811
+ ((failed_count++))
801
812
  ;;
802
813
  esac
803
814
  done
@@ -817,21 +828,21 @@ _install_specific_tools() {
817
828
  osint)
818
829
  import "@/tools/osint/robin/common"
819
830
  _robin_print_disclaimer
820
- _batch_tool_action "osint" "install" "${tools[@]}"
831
+ _batch_tool_action "osint" "install" "${tools[@]}" || return 1
821
832
  ;;
822
833
  network)
823
- _batch_tool_action "network" "install" "${tools[@]}"
834
+ _batch_tool_action "network" "install" "${tools[@]}" || return 1
824
835
  ;;
825
836
  utils)
826
- _batch_tool_action "utils" "install" "${tools[@]}"
837
+ _batch_tool_action "utils" "install" "${tools[@]}" || return 1
827
838
  ;;
828
839
  security)
829
- _batch_tool_action "security" "install" "${tools[@]}"
840
+ _batch_tool_action "security" "install" "${tools[@]}" || return 1
830
841
  ;;
831
842
  supabase)
832
843
  import "@/tools/deploy/supabase/install"
833
844
  install_supabase
834
- case $? in 0) log_success "Supabase CLI installed";; 2) log_info "Supabase CLI already installed";; 1) log_error "Failed to install Supabase CLI";; esac
845
+ case $? in 0) log_success "Supabase CLI installed";; 2) log_info "Supabase CLI already installed";; *) log_error "Failed to install Supabase CLI"; return 1;; esac
835
846
  ;;
836
847
  *)
837
848
  log_warn "Unknown install target: $module"
@@ -839,4 +850,5 @@ _install_specific_tools() {
839
850
  return 1
840
851
  ;;
841
852
  esac
853
+ (( ${failed_count:-0} == 0 ))
842
854
  }
@@ -209,6 +209,7 @@ _list_ai() {
209
209
  table_row "Copilot-Termux" "--copilot-termux" "copilot" "$(_check_cmd "copilot")"
210
210
  table_row "Supercode CLI" "--supercode-cli" "supercode" "$(_check_cmd "supercode")"
211
211
  table_row "Puter CLI" "--puter" "puter" "$(_check_cmd "puter")"
212
+ table_row "KeelCode" "--keelcode" "keelcode" "$(_check_cmd "keelcode")"
212
213
  table_end
213
214
 
214
215
  echo
@@ -452,6 +453,7 @@ _list_utils() {
452
453
  table_row "httptmux (API client)" "--httptmux" "httptmux" "$(_check_cmd "httptmux")"
453
454
  table_row "Zork (text adventure)" "--zork" "zork" "$(_check_cmd "zork")"
454
455
  table_row "QR Code Generator" "--qrcode" "qrcode" "$(_check_cmd "qrcode")"
456
+ table_row "SuperFile" "--superfile" "spf" "$(_check_cmd "spf")"
455
457
  table_end
456
458
 
457
459
  echo
@@ -178,6 +178,7 @@ _reinstall_specific_tools() {
178
178
  local module="$1"
179
179
  shift
180
180
  local -a tools=("$@")
181
+ local failed_count=0
181
182
 
182
183
  case "$module" in
183
184
  ai)
@@ -299,6 +300,10 @@ _reinstall_specific_tools() {
299
300
  reinstall_puter
300
301
  case $? in 0) ((reinstalled_count++));; 1) ((failed_count++));; esac
301
302
  ;;
303
+ keelcode)
304
+ reinstall_keelcode
305
+ case $? in 0) ((reinstalled_count++));; 1) ((failed_count++));; esac
306
+ ;;
302
307
  qoder)
303
308
  reinstall_qoder
304
309
  case $? in 0) ((reinstalled_count++));; 1) ((failed_count++));; esac
@@ -349,6 +354,7 @@ _reinstall_specific_tools() {
349
354
  ;;
350
355
  *)
351
356
  log_warn "Unknown AI tool: --$tool"
357
+ ((failed_count++))
352
358
  ;;
353
359
  esac
354
360
  done
@@ -391,6 +397,7 @@ _reinstall_specific_tools() {
391
397
  ;;
392
398
  *)
393
399
  log_warn "Unknown database: --$tool"
400
+ ((failed_count++))
394
401
  ;;
395
402
  esac
396
403
  done
@@ -501,6 +508,7 @@ _reinstall_specific_tools() {
501
508
  ;;
502
509
  *)
503
510
  log_warn "Unknown tool: --$tool"
511
+ ((failed_count++))
504
512
  ;;
505
513
  esac
506
514
  done
@@ -547,6 +555,7 @@ _reinstall_specific_tools() {
547
555
  ;;
548
556
  *)
549
557
  log_warn "Unknown game: --$tool"
558
+ ((failed_count++))
550
559
  ;;
551
560
  esac
552
561
  done
@@ -613,6 +622,7 @@ _reinstall_specific_tools() {
613
622
  ;;
614
623
  *)
615
624
  log_warn "Unknown node module: --$tool"
625
+ ((failed_count++))
616
626
  ;;
617
627
  esac
618
628
  done
@@ -667,6 +677,7 @@ _reinstall_specific_tools() {
667
677
  ;;
668
678
  *)
669
679
  log_warn "Unknown language: --$tool"
680
+ ((failed_count++))
670
681
  ;;
671
682
  esac
672
683
  done
@@ -729,6 +740,7 @@ _reinstall_specific_tools() {
729
740
  ;;
730
741
  *)
731
742
  log_warn "Unknown plugin: --$tool"
743
+ ((failed_count++))
732
744
  ;;
733
745
  esac
734
746
  done
@@ -763,6 +775,7 @@ _reinstall_specific_tools() {
763
775
  ;;
764
776
  *)
765
777
  log_warn "Unknown editor component: --$tool"
778
+ ((failed_count++))
766
779
  ;;
767
780
  esac
768
781
  done
@@ -801,6 +814,7 @@ _reinstall_specific_tools() {
801
814
  ;;
802
815
  *)
803
816
  log_warn "Unknown UI component: --$tool"
817
+ ((failed_count++))
804
818
  ;;
805
819
  esac
806
820
  done
@@ -827,6 +841,7 @@ _reinstall_specific_tools() {
827
841
  ;;
828
842
  *)
829
843
  log_warn "Unknown automation tool: --$tool"
844
+ ((failed_count++))
830
845
  ;;
831
846
  esac
832
847
  done
@@ -843,16 +858,16 @@ _reinstall_specific_tools() {
843
858
  osint)
844
859
  import "@/tools/osint/robin/common"
845
860
  _robin_print_disclaimer
846
- _batch_tool_action "osint" "reinstall" "${tools[@]}"
861
+ _batch_tool_action "osint" "reinstall" "${tools[@]}" || return 1
847
862
  ;;
848
863
  network)
849
- _batch_tool_action "network" "reinstall" "${tools[@]}"
864
+ _batch_tool_action "network" "reinstall" "${tools[@]}" || return 1
850
865
  ;;
851
866
  utils)
852
- _batch_tool_action "utils" "reinstall" "${tools[@]}"
867
+ _batch_tool_action "utils" "reinstall" "${tools[@]}" || return 1
853
868
  ;;
854
869
  security|deploy)
855
- _batch_tool_action "$module" "reinstall" "${tools[@]}"
870
+ _batch_tool_action "$module" "reinstall" "${tools[@]}" || return 1
856
871
  ;;
857
872
  *)
858
873
  log_warn "Unknown reinstall target: $module"
@@ -860,4 +875,5 @@ _reinstall_specific_tools() {
860
875
  return 1
861
876
  ;;
862
877
  esac
878
+ (( ${failed_count:-0} == 0 ))
863
879
  }
@@ -220,7 +220,7 @@ _update_try_curl() {
220
220
 
221
221
  log_info "Trying the official curl installer..."
222
222
 
223
- if ! curl --fail --silent --show-error --location \
223
+ if ! curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' \
224
224
  "https://api.github.com/repos/israelmarques1024-dotcom/karnel-termux/releases/latest" \
225
225
  -o "$meta"; then
226
226
  rm -f "$meta" "$installer" "$sumfile"
@@ -234,10 +234,10 @@ _update_try_curl() {
234
234
  return 1
235
235
  fi
236
236
 
237
- if ! curl --fail --silent --show-error --location \
237
+ if ! curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' \
238
238
  "https://github.com/israelmarques1024-dotcom/karnel-termux/releases/download/$tag/karnel-termux-install.sh.sha256" \
239
239
  -o "$sumfile" ||
240
- ! curl --fail --silent --show-error --location \
240
+ ! curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' \
241
241
  "https://github.com/israelmarques1024-dotcom/karnel-termux/releases/download/$tag/karnel-termux-install.sh" \
242
242
  -o "$installer"; then
243
243
  rm -f "$meta" "$installer" "$sumfile"
@@ -252,7 +252,7 @@ _update_try_curl() {
252
252
 
253
253
  rm -f "$meta" "$sumfile"
254
254
 
255
- if bash "$installer"; then
255
+ if bash "$installer" --ref "$tag"; then
256
256
  rm -f "$installer"
257
257
  log_success "Karnel-Termux updated via curl (v$tag)"
258
258
  return 0
@@ -282,8 +282,13 @@ _update_latest_release_tag() {
282
282
  _verify_sha256() {
283
283
  local file="$1" sumfile="$2"
284
284
  local expected actual
285
- expected=$(awk 'NR == 1 { print $1 }' "$sumfile")
286
- [[ -n "$expected" ]] || return 1
285
+ local -a checksum_lines
286
+
287
+ mapfile -t checksum_lines <"$sumfile" || return 1
288
+ if [[ ${#checksum_lines[@]} -ne 1 ]] || [[ ! "${checksum_lines[0]}" =~ ^([0-9a-f]{64})[[:space:]]+\*?karnel-termux-install\.sh$ ]]; then
289
+ return 1
290
+ fi
291
+ expected="${BASH_REMATCH[1]}"
287
292
  if command -v sha256sum &>/dev/null; then
288
293
  actual=$(sha256sum "$file" | awk '{ print $1 }')
289
294
  elif command -v node &>/dev/null; then
@@ -2,6 +2,7 @@
2
2
 
3
3
  import "@/utils/log"
4
4
  import "@/utils/colors"
5
+ import "@/utils/uninstall"
5
6
 
6
7
  ZSH_PLUGINS_DIR="$HOME/.zsh-plugins"
7
8
  OH_MY_ZSH_DIR="$HOME/.oh-my-zsh"
@@ -226,8 +227,12 @@ uninstall_oh_my_zsh() {
226
227
 
227
228
  log_info "Uninstalling Oh My Zsh..."
228
229
 
229
- if rm -rf "$OH_MY_ZSH_DIR" &>>"$LOG_FILE"; then
230
+ local remove_rc=0
231
+ confirm_remove_paths "Oh My Zsh" "$OH_MY_ZSH_DIR" &>>"$LOG_FILE" || remove_rc=$?
232
+ if [[ "$remove_rc" -eq 0 ]]; then
230
233
  log_success "Oh My Zsh uninstalled"
234
+ elif [[ "$remove_rc" -eq 2 ]]; then
235
+ log_info "Oh My Zsh configuration preserved"
231
236
  else
232
237
  log_error "Failed to uninstall Oh My Zsh"
233
238
  return 1
@@ -248,7 +253,7 @@ uninstall_shell() {
248
253
 
249
254
  local rc=0
250
255
  _uninstall_shell_plugins_wrapper || rc=$?
251
- loading "Removing Oh My Zsh" uninstall_oh_my_zsh
256
+ uninstall_oh_my_zsh || rc=1
252
257
 
253
258
  echo
254
259
  separator
@@ -61,6 +61,7 @@ AI_TOOLS_REGISTRY=(
61
61
  "openspec:OpenSpec SDD Framework:openspec"
62
62
  "supercode-cli:Supercode CLI:supercode"
63
63
  "puter:Puter CLI:puter"
64
+ "keelcode:KeelCode:keelcode"
64
65
  "copilot-termux:Copilot-Termux:copilot"
65
66
  "qoder:Qoder:qodercli"
66
67
  "ampcode:AMP Code CLI:amp"
@@ -0,0 +1,16 @@
1
+ # KeelCode
2
+
3
+ KeelCode is a hosted coding-agent CLI from KeelCode AI.
4
+
5
+ - Official package: `@keelcode-ai/keelcode`
6
+ - Command: `keelcode`
7
+ - Homepage: https://keelcode.ai
8
+
9
+ ## Lifecycle
10
+
11
+ ```bash
12
+ karnel install ai --keelcode
13
+ karnel update ai --keelcode
14
+ karnel reinstall ai --keelcode
15
+ karnel uninstall ai --keelcode
16
+ ```
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env bash
2
+
3
+ import "@/utils/log"
4
+ import "@/utils/version"
5
+
6
+ KEELCODE_PACKAGE="@keelcode-ai/keelcode"
7
+
8
+ install_keelcode() {
9
+ if command -v keelcode &>/dev/null; then
10
+ log_info "KeelCode is already installed"
11
+ return 2
12
+ fi
13
+
14
+ log_info "Installing KeelCode..."
15
+ local output rc
16
+ output="$(npm install -g "$KEELCODE_PACKAGE" 2>&1)"
17
+ rc=$?
18
+ printf '%s\n' "$output" | tail -3
19
+ if ((rc != 0)); then
20
+ log_error "Failed to install KeelCode"
21
+ return 1
22
+ fi
23
+ if ! command -v keelcode &>/dev/null; then
24
+ log_error "KeelCode binary was not found after npm installation"
25
+ return 1
26
+ fi
27
+ command -v termux-fix-shebang &>/dev/null && termux-fix-shebang "$(command -v keelcode)" &>/dev/null || true
28
+ log_success "KeelCode installed"
29
+ }
30
+
31
+ uninstall_keelcode() {
32
+ if ! command -v keelcode &>/dev/null; then
33
+ log_info "KeelCode is not installed"
34
+ return 2
35
+ fi
36
+
37
+ log_info "Uninstalling KeelCode..."
38
+ local output rc
39
+ output="$(npm uninstall -g "$KEELCODE_PACKAGE" 2>&1)"
40
+ rc=$?
41
+ printf '%s\n' "$output" | tail -3
42
+ if ((rc != 0)); then
43
+ log_error "Failed to uninstall KeelCode"
44
+ return 1
45
+ fi
46
+ log_success "KeelCode uninstalled"
47
+ }
48
+
49
+ update_keelcode() {
50
+ _check_update_needed "KeelCode" \
51
+ "$(_get_installed_npm_version "$KEELCODE_PACKAGE")" \
52
+ "$(_get_remote_npm_version "$KEELCODE_PACKAGE")" \
53
+ _do_update_keelcode
54
+ }
55
+
56
+ _do_update_keelcode() {
57
+ local output rc
58
+ output="$(npm update -g "$KEELCODE_PACKAGE" 2>&1)"
59
+ rc=$?
60
+ printf '%s\n' "$output" | tail -3
61
+ if ((rc != 0)); then
62
+ log_error "Failed to update KeelCode"
63
+ return 1
64
+ fi
65
+ command -v keelcode &>/dev/null && command -v termux-fix-shebang &>/dev/null && termux-fix-shebang "$(command -v keelcode)" &>/dev/null || true
66
+ }
67
+
68
+ reinstall_keelcode() {
69
+ uninstall_keelcode || [[ $? -eq 2 ]] || return 1
70
+ install_keelcode
71
+ }
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
3
  import "@/utils/log"
4
+ import "@/utils/uninstall"
4
5
  import "@/utils/version"
5
6
 
6
7
  LOG_FILE="$KARNEL_CACHE/install_editor.log"
@@ -67,9 +68,14 @@ install_nvchad() {
67
68
 
68
69
  _uninstall_nvchad_impl() {
69
70
  if [[ -d "$HOME/.config/nvim" ]]; then
70
- rm -rf ~/.config/nvim &>>"$LOG_FILE"
71
- rm -rf ~/.local/state/nvim &>>"$LOG_FILE"
72
- rm -rf ~/.local/share/nvim &>>"$LOG_FILE"
71
+ local remove_rc=0
72
+ confirm_remove_paths "NvChad" "$HOME/.config/nvim" "$HOME/.local/state/nvim" "$HOME/.local/share/nvim" &>>"$LOG_FILE" || remove_rc=$?
73
+ if [[ "$remove_rc" -eq 2 ]]; then
74
+ log_info "NvChad configuration preserved"
75
+ elif [[ "$remove_rc" -ne 0 ]]; then
76
+ log_error "Failed to remove NvChad configuration"
77
+ return 1
78
+ fi
73
79
  rm -rf "$NVCHAD_DIR" &>>"$LOG_FILE"
74
80
  log_success "NvChad uninstalled"
75
81
  else
@@ -748,19 +748,24 @@ _plugin_fetch_registry() {
748
748
  _plugin_registry_entry_for() {
749
749
  local registry="$1"
750
750
  local selector="$2"
751
- local filter result
751
+ local filter result count
752
752
 
753
753
  if _plugin_repo_is_valid "$selector"; then
754
- filter='.plugins[] | select(.repo == $selector)'
754
+ filter='[.plugins[] | select(.repo == $selector)]'
755
755
  elif _plugin_name_is_valid "$selector"; then
756
- filter='.plugins[] | select(.name == $selector)'
756
+ filter='[.plugins[] | select(.name == $selector)]'
757
757
  else
758
758
  return 1
759
759
  fi
760
760
 
761
761
  result="$(jq -c --arg selector "$selector" "$filter" "$registry")" || return 1
762
- [[ -n "$result" ]] || return 1
763
- printf '%s\n' "$result"
762
+ count="$(jq 'length' <<<"$result")" || return 1
763
+ (( count > 0 )) || return 1
764
+ if (( count > 1 )); then
765
+ log_error "Repository '$selector' provides multiple plugins; install one by its approved name."
766
+ return 2
767
+ fi
768
+ jq -c '.[0]' <<<"$result"
764
769
  }
765
770
 
766
771
  _plugin_registry_entry_matches_manifest() {
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
3
  import "@/utils/log"
4
+ import "@/utils/uninstall"
4
5
 
5
6
  LOG_FILE="$KARNEL_CACHE/install_shell.log"
6
7
  ZSH_PLUGINS_DIR="$HOME/.zsh-plugins"
@@ -38,7 +39,11 @@ _batch_shell() {
38
39
  for tool in "${SHELL_PLUGINS[@]}"; do
39
40
  func_name="${action}_${tool//-/_}"
40
41
  if declare -f "$func_name" &>/dev/null; then
41
- loading "${action_past^}ing ${tool}" "$func_name"
42
+ if [[ "$action" == "uninstall" ]]; then
43
+ "$func_name"
44
+ else
45
+ loading "${action_past^}ing ${tool}" "$func_name"
46
+ fi
42
47
  case $? in 0) ((count++));; 1) ((failed++));; esac
43
48
  fi
44
49
  ((current++))
@@ -60,11 +60,17 @@ _uninstall_better_npm_impl() {
60
60
  return 0
61
61
  fi
62
62
 
63
- rm -rf "$ZSH_PLUGINS_DIR/zsh-better-npm-completion"
63
+ local remove_rc=0
64
+ confirm_remove_paths "zsh-better-npm-completion" "$ZSH_PLUGINS_DIR/zsh-better-npm-completion" || remove_rc=$?
65
+ if [[ "$remove_rc" -eq 2 ]]; then
66
+ log_info "zsh-better-npm-completion configuration and data preserved"
67
+ return 0
68
+ fi
69
+ return "$remove_rc"
64
70
  }
65
71
 
66
72
  uninstall_better_npm() {
67
- loading "Uninstalling zsh-better-npm-completion" _uninstall_better_npm_impl
73
+ _uninstall_better_npm_impl
68
74
  }
69
75
 
70
76
  _update_better_npm_impl() {
@@ -60,11 +60,17 @@ _uninstall_fzf_tab_impl() {
60
60
  return 0
61
61
  fi
62
62
 
63
- rm -rf "$ZSH_PLUGINS_DIR/fzf-tab"
63
+ local remove_rc=0
64
+ confirm_remove_paths "fzf-tab" "$ZSH_PLUGINS_DIR/fzf-tab" || remove_rc=$?
65
+ if [[ "$remove_rc" -eq 2 ]]; then
66
+ log_info "fzf-tab configuration and data preserved"
67
+ return 0
68
+ fi
69
+ return "$remove_rc"
64
70
  }
65
71
 
66
72
  uninstall_fzf_tab() {
67
- loading "Uninstalling fzf-tab" _uninstall_fzf_tab_impl
73
+ _uninstall_fzf_tab_impl
68
74
  }
69
75
 
70
76
  _update_fzf_tab_impl() {
@@ -60,11 +60,17 @@ _uninstall_history_substring_impl() {
60
60
  return 0
61
61
  fi
62
62
 
63
- rm -rf "$ZSH_PLUGINS_DIR/zsh-history-substring-search"
63
+ local remove_rc=0
64
+ confirm_remove_paths "zsh-history-substring-search" "$ZSH_PLUGINS_DIR/zsh-history-substring-search" || remove_rc=$?
65
+ if [[ "$remove_rc" -eq 2 ]]; then
66
+ log_info "zsh-history-substring-search configuration and data preserved"
67
+ return 0
68
+ fi
69
+ return "$remove_rc"
64
70
  }
65
71
 
66
72
  uninstall_history_substring() {
67
- loading "Uninstalling zsh-history-substring-search" _uninstall_history_substring_impl
73
+ _uninstall_history_substring_impl
68
74
  }
69
75
 
70
76
  _update_history_substring_impl() {
@@ -60,11 +60,17 @@ _uninstall_powerlevel10k_impl() {
60
60
  return 0
61
61
  fi
62
62
 
63
- rm -rf "$ZSH_PLUGINS_DIR/powerlevel10k"
63
+ local remove_rc=0
64
+ confirm_remove_paths "powerlevel10k" "$ZSH_PLUGINS_DIR/powerlevel10k" || remove_rc=$?
65
+ if [[ "$remove_rc" -eq 2 ]]; then
66
+ log_info "powerlevel10k configuration and data preserved"
67
+ return 0
68
+ fi
69
+ return "$remove_rc"
64
70
  }
65
71
 
66
72
  uninstall_powerlevel10k() {
67
- loading "Uninstalling powerlevel10k" _uninstall_powerlevel10k_impl
73
+ _uninstall_powerlevel10k_impl
68
74
  }
69
75
 
70
76
  _update_powerlevel10k_impl() {
@@ -60,11 +60,17 @@ _uninstall_you_should_use_impl() {
60
60
  return 0
61
61
  fi
62
62
 
63
- rm -rf "$ZSH_PLUGINS_DIR/zsh-you-should-use"
63
+ local remove_rc=0
64
+ confirm_remove_paths "zsh-you-should-use" "$ZSH_PLUGINS_DIR/zsh-you-should-use" || remove_rc=$?
65
+ if [[ "$remove_rc" -eq 2 ]]; then
66
+ log_info "zsh-you-should-use configuration and data preserved"
67
+ return 0
68
+ fi
69
+ return "$remove_rc"
64
70
  }
65
71
 
66
72
  uninstall_you_should_use() {
67
- loading "Uninstalling zsh-you-should-use" _uninstall_you_should_use_impl
73
+ _uninstall_you_should_use_impl
68
74
  }
69
75
 
70
76
  _update_you_should_use_impl() {
@@ -60,11 +60,17 @@ _uninstall_zsh_autopair_impl() {
60
60
  return 0
61
61
  fi
62
62
 
63
- rm -rf "$ZSH_PLUGINS_DIR/zsh-autopair"
63
+ local remove_rc=0
64
+ confirm_remove_paths "zsh-autopair" "$ZSH_PLUGINS_DIR/zsh-autopair" || remove_rc=$?
65
+ if [[ "$remove_rc" -eq 2 ]]; then
66
+ log_info "zsh-autopair configuration and data preserved"
67
+ return 0
68
+ fi
69
+ return "$remove_rc"
64
70
  }
65
71
 
66
72
  uninstall_zsh_autopair() {
67
- loading "Uninstalling zsh-autopair" _uninstall_zsh_autopair_impl
73
+ _uninstall_zsh_autopair_impl
68
74
  }
69
75
 
70
76
  _update_zsh_autopair_impl() {
@@ -60,11 +60,17 @@ _uninstall_zsh_autosuggestions_impl() {
60
60
  return 0
61
61
  fi
62
62
 
63
- rm -rf "$ZSH_PLUGINS_DIR/zsh-autosuggestions"
63
+ local remove_rc=0
64
+ confirm_remove_paths "zsh-autosuggestions" "$ZSH_PLUGINS_DIR/zsh-autosuggestions" || remove_rc=$?
65
+ if [[ "$remove_rc" -eq 2 ]]; then
66
+ log_info "zsh-autosuggestions configuration and data preserved"
67
+ return 0
68
+ fi
69
+ return "$remove_rc"
64
70
  }
65
71
 
66
72
  uninstall_zsh_autosuggestions() {
67
- loading "Uninstalling zsh-autosuggestions" _uninstall_zsh_autosuggestions_impl
73
+ _uninstall_zsh_autosuggestions_impl
68
74
  }
69
75
 
70
76
  _update_zsh_autosuggestions_impl() {
@@ -60,11 +60,17 @@ _uninstall_zsh_completions_impl() {
60
60
  return 0
61
61
  fi
62
62
 
63
- rm -rf "$ZSH_PLUGINS_DIR/zsh-completions"
63
+ local remove_rc=0
64
+ confirm_remove_paths "zsh-completions" "$ZSH_PLUGINS_DIR/zsh-completions" || remove_rc=$?
65
+ if [[ "$remove_rc" -eq 2 ]]; then
66
+ log_info "zsh-completions configuration and data preserved"
67
+ return 0
68
+ fi
69
+ return "$remove_rc"
64
70
  }
65
71
 
66
72
  uninstall_zsh_completions() {
67
- loading "Uninstalling zsh-completions" _uninstall_zsh_completions_impl
73
+ _uninstall_zsh_completions_impl
68
74
  }
69
75
 
70
76
  _update_zsh_completions_impl() {
@@ -60,11 +60,17 @@ _uninstall_zsh_defer_impl() {
60
60
  return 2
61
61
  fi
62
62
 
63
- rm -rf "$ZSH_PLUGINS_DIR/zsh-defer"
63
+ local remove_rc=0
64
+ confirm_remove_paths "zsh-defer" "$ZSH_PLUGINS_DIR/zsh-defer" || remove_rc=$?
65
+ if [[ "$remove_rc" -eq 2 ]]; then
66
+ log_info "zsh-defer configuration and data preserved"
67
+ return 0
68
+ fi
69
+ return "$remove_rc"
64
70
  }
65
71
 
66
72
  uninstall_zsh_defer() {
67
- loading "Uninstalling zsh-defer" _uninstall_zsh_defer_impl
73
+ _uninstall_zsh_defer_impl
68
74
  }
69
75
 
70
76
  _update_zsh_defer_impl() {
@@ -47,11 +47,17 @@ _uninstall_zsh_syntax_highlighting_impl() {
47
47
  return 0
48
48
  fi
49
49
 
50
- rm -rf "$ZSH_PLUGINS_DIR/zsh-syntax-highlighting"
50
+ local remove_rc=0
51
+ confirm_remove_paths "zsh-syntax-highlighting" "$ZSH_PLUGINS_DIR/zsh-syntax-highlighting" || remove_rc=$?
52
+ if [[ "$remove_rc" -eq 2 ]]; then
53
+ log_info "zsh-syntax-highlighting configuration and data preserved"
54
+ return 0
55
+ fi
56
+ return "$remove_rc"
51
57
  }
52
58
 
53
59
  uninstall_zsh_syntax_highlighting() {
54
- loading "Uninstalling zsh-syntax-highlighting" _uninstall_zsh_syntax_highlighting_impl
60
+ _uninstall_zsh_syntax_highlighting_impl
55
61
  }
56
62
 
57
63
  _update_zsh_syntax_highlighting_impl() {
@@ -16,6 +16,7 @@ TOOLS_PACKAGES=(
16
16
  "httptmux"
17
17
  "zork"
18
18
  "qrcode"
19
+ "superfile"
19
20
  )
20
21
 
21
22
  TOOLS_DISPLAY=(
@@ -30,6 +31,7 @@ TOOLS_DISPLAY=(
30
31
  "httptmux (interactive API client)"
31
32
  "Zork (text adventure games I, II, III)"
32
33
  "QR Code (link-to-QR generator)"
34
+ "SuperFile (terminal file manager)"
33
35
  )
34
36
 
35
37
  for _tool in "${TOOLS_PACKAGES[@]}"; do
@@ -0,0 +1,19 @@
1
+ # SuperFile
2
+
3
+ SuperFile is a terminal file manager from yorukot.
4
+
5
+ - Official source: https://github.com/yorukot/superfile
6
+ - Pinned release: `v1.5.0`
7
+ - Pinned commit: `fe41cef5e9ee5b16e79981540c49f932a3d4d249`
8
+ - Command: `spf`
9
+
10
+ Karnel builds the pinned release from source with Go. The checkout is kept in `$KARNEL_DATA/superfile` and each build stages a replacement before installing the binary.
11
+
12
+ ## Lifecycle
13
+
14
+ ```bash
15
+ karnel install utils --superfile
16
+ karnel update utils --superfile
17
+ karnel reinstall utils --superfile
18
+ karnel uninstall utils --superfile
19
+ ```
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env bash
2
+
3
+ import "@/utils/log"
4
+
5
+ SUPERFILE_VERSION="v1.5.0"
6
+ SUPERFILE_COMMIT="fe41cef5e9ee5b16e79981540c49f932a3d4d249"
7
+ SUPERFILE_REPOSITORY="https://github.com/yorukot/superfile.git"
8
+ SUPERFILE_DATA_DIR="$KARNEL_DATA/superfile"
9
+ SUPERFILE_BIN="$PREFIX/bin/spf"
10
+
11
+ _superfile_dependencies() {
12
+ local package binary
13
+ while IFS=: read -r package binary; do
14
+ if ! command -v "$binary" &>/dev/null; then
15
+ if ! pkg install "$package" -y &>>"$KARNEL_CACHE/install_utils.log"; then
16
+ log_error "Failed to install $package"
17
+ return 1
18
+ fi
19
+ fi
20
+ done <<'EOF'
21
+ git:git
22
+ golang:go
23
+ EOF
24
+ }
25
+
26
+ _build_superfile() {
27
+ local staging_dir old_dir
28
+ mkdir -p "$KARNEL_DATA" "$PREFIX/bin" "${KARNEL_CACHE}"
29
+ staging_dir="$(mktemp -d "$KARNEL_DATA/.superfile.XXXXXX")" || return 1
30
+
31
+ if ! git clone --depth 1 --branch "$SUPERFILE_VERSION" "$SUPERFILE_REPOSITORY" "$staging_dir/source" &>>"$KARNEL_CACHE/install_utils.log" ||
32
+ [[ "$(git -C "$staging_dir/source" rev-parse HEAD)" != "$SUPERFILE_COMMIT" ]] ||
33
+ ! go build -C "$staging_dir/source" -trimpath -ldflags='-s -w' -o "$staging_dir/spf" . &>>"$KARNEL_CACHE/install_utils.log" ||
34
+ [[ ! -x "$staging_dir/spf" ]]; then
35
+ rm -rf "$staging_dir"
36
+ log_error "Failed to build SuperFile $SUPERFILE_VERSION"
37
+ return 1
38
+ fi
39
+
40
+ old_dir="$KARNEL_DATA/.superfile.previous.$$"
41
+ if [[ -d "$SUPERFILE_DATA_DIR" ]]; then
42
+ mv "$SUPERFILE_DATA_DIR" "$old_dir" || { rm -rf "$staging_dir"; return 1; }
43
+ fi
44
+ if ! mv "$staging_dir/source" "$SUPERFILE_DATA_DIR" || ! mv -f "$staging_dir/spf" "$SUPERFILE_BIN"; then
45
+ rm -rf "$staging_dir" "$SUPERFILE_DATA_DIR"
46
+ [[ -d "$old_dir" ]] && mv "$old_dir" "$SUPERFILE_DATA_DIR"
47
+ log_error "Failed to replace SuperFile"
48
+ return 1
49
+ fi
50
+ rm -rf "$staging_dir" "$old_dir"
51
+ }
52
+
53
+ install_superfile() {
54
+ if command -v spf &>/dev/null; then
55
+ log_info "SuperFile is already installed"
56
+ return 2
57
+ fi
58
+
59
+ log_info "Installing SuperFile $SUPERFILE_VERSION..."
60
+ _superfile_dependencies || return 1
61
+ _build_superfile || return 1
62
+ log_success "SuperFile installed"
63
+ }
64
+
65
+ uninstall_superfile() {
66
+ if [[ ! -e "$SUPERFILE_BIN" && ! -d "$SUPERFILE_DATA_DIR" ]]; then
67
+ log_info "SuperFile is not installed"
68
+ return 2
69
+ fi
70
+
71
+ log_info "Uninstalling SuperFile..."
72
+ if ! rm -f "$SUPERFILE_BIN" || ! rm -rf "$SUPERFILE_DATA_DIR"; then
73
+ log_error "Failed to uninstall SuperFile"
74
+ return 1
75
+ fi
76
+ log_success "SuperFile uninstalled"
77
+ }
78
+
79
+ update_superfile() {
80
+ log_info "Updating SuperFile to $SUPERFILE_VERSION..."
81
+ _superfile_dependencies || return 1
82
+ _build_superfile || return 1
83
+ log_success "SuperFile updated"
84
+ }
85
+
86
+ reinstall_superfile() {
87
+ uninstall_superfile || [[ $? -eq 2 ]] || return 1
88
+ install_superfile
89
+ }
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env bash
2
+
3
+ confirm_remove_paths() {
4
+ local label="$1"
5
+ shift
6
+ local answer path
7
+ local -a existing=()
8
+
9
+ for path in "$@"; do
10
+ [[ -e "$path" || -L "$path" ]] && existing+=("$path")
11
+ done
12
+ (( ${#existing[@]} > 0 )) || return 0
13
+
14
+ read_confirm_default "Remove $label configuration and data?" "n" answer || return 2
15
+ [[ "$answer" == "y" ]] || return 2
16
+
17
+ rm -rf -- "${existing[@]}"
18
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karnel-termux",
3
- "version": "4.13.7",
3
+ "version": "4.13.8",
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"