karnel-termux 4.17.21 → 4.17.23
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 +5 -4
- package/docs/CHANGELOG.md +8 -0
- package/install.sh +20 -5
- package/karnel/RELEASE_COMMIT +1 -1
- package/karnel/cli/commands/agent.sh +9 -5
- package/karnel/cli/commands/brain.sh +18 -14
- package/karnel/cli/commands/doctor/fixes.sh +4 -4
- package/karnel/cli/commands/doctor.sh +4 -2
- package/karnel/cli/commands/ia.sh +5 -1
- package/karnel/cli/commands/pg.sh +5 -2
- package/karnel/cli/commands/restore.sh +3 -0
- package/karnel/cli/commands/update.sh +18 -0
- package/karnel/cli/commands/upgrade.sh +9 -2
- package/karnel/cli/commands/voice.sh +4 -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/lang/bun/install.sh +2 -2
- 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/qrcode.py +1 -0
- package/karnel/tools/utils/websites/websites.py +1 -0
- package/karnel/tools/voice/uninstall.sh +1 -0
- package/karnel/utils/agent_actions.sh +8 -0
- package/karnel/utils/agent_llm.sh +7 -7
- 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
|
@@ -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.17.
|
|
11
|
+
<img src="https://img.shields.io/badge/version-4.17.22-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">
|
|
@@ -78,7 +78,7 @@ Why it's great:
|
|
|
78
78
|
### Via checksummed GitHub release (recommended)
|
|
79
79
|
|
|
80
80
|
```bash
|
|
81
|
-
version=4.17.
|
|
81
|
+
version=4.17.22
|
|
82
82
|
tmpdir=$(mktemp -d) && trap 'rm -rf "$tmpdir"' EXIT
|
|
83
83
|
base="https://github.com/israelmarques1024-dotcom/karnel-termux/releases/download/v$version"
|
|
84
84
|
curl -fsSL "$base/karnel-termux-install.sh" -o "$tmpdir/karnel-termux-install.sh"
|
|
@@ -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/docs/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ layout: base
|
|
|
6
6
|
|
|
7
7
|
# Documentation Changelog
|
|
8
8
|
|
|
9
|
+
## 4.17.22
|
|
10
|
+
|
|
11
|
+
- **Data safety and correctness (8):** restore rejects ambiguous multiple archives; Brain preserves same-day title collisions, uses file paths for AI context, initializes/pushes `main`, detects missing `origin`, and supports editors with arguments; PostgreSQL backup filenames are path-safe; AI-session persistence escapes JSON correctly.
|
|
12
|
+
- **Agent safety (3):** positional prompts retain all words, zero-valued execution/context limits are rejected, and PLAN mode rejects shell syntax plus destructive `find`/in-place operations that bypassed its read-only contract.
|
|
13
|
+
- **Installer reliability (1):** Bun proot installation/update no longer reject safe archives before extraction.
|
|
14
|
+
- **Regression coverage:** added critical CLI contracts and strengthened Brain reciprocal-relation coverage; the isolated full suite passes.
|
|
15
|
+
- Version references bumped to `4.17.22`.
|
|
16
|
+
|
|
9
17
|
## 4.17.21
|
|
10
18
|
|
|
11
19
|
- **Official-site routing:** `karnel open`, npm package metadata, and the GitHub/npm README now point to the Vercel production site, `https://karneltermux.vercel.app`, rather than the secondary GitHub Pages mirror.
|
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
|
+
9e1cc56cd0e413f5135180c07ae5c9cea021e4ba
|
|
@@ -255,10 +255,11 @@ agent_parse_args() {
|
|
|
255
255
|
AGENT_PROMPT=""
|
|
256
256
|
AGENT_SHOW_HELP=0
|
|
257
257
|
AGENT_YES=0
|
|
258
|
-
local prev=""
|
|
258
|
+
local prev="" prompt_set=0
|
|
259
|
+
local -a positional=()
|
|
259
260
|
for arg in "$@"; do
|
|
260
261
|
case "$prev" in
|
|
261
|
-
-p | --prompt) AGENT_PROMPT="$arg"; prev=""; continue ;;
|
|
262
|
+
-p | --prompt) AGENT_PROMPT="$arg"; prompt_set=1; prev=""; continue ;;
|
|
262
263
|
-m | --model) AGENT_MODEL="$arg"; prev=""; continue ;;
|
|
263
264
|
-u | --endpoint) AGENT_ENDPOINT="$arg"; prev=""; continue ;;
|
|
264
265
|
-t | --temperature) AGENT_TEMPERATURE="$arg"; prev=""; continue ;;
|
|
@@ -267,7 +268,7 @@ agent_parse_args() {
|
|
|
267
268
|
--max-tokens) AGENT_MAX_TOKENS="$arg"; prev=""; continue ;;
|
|
268
269
|
esac
|
|
269
270
|
case "$arg" in
|
|
270
|
-
-p=* | --prompt=*) AGENT_PROMPT="${arg#*=}" ;;
|
|
271
|
+
-p=* | --prompt=*) AGENT_PROMPT="${arg#*=}"; prompt_set=1 ;;
|
|
271
272
|
-m=* | --model=*) AGENT_MODEL="${arg#*=}" ;;
|
|
272
273
|
-u=* | --endpoint=*) AGENT_ENDPOINT="${arg#*=}" ;;
|
|
273
274
|
-t=* | --temperature=*) AGENT_TEMPERATURE="${arg#*=}" ;;
|
|
@@ -280,9 +281,12 @@ agent_parse_args() {
|
|
|
280
281
|
-y | --yes) AGENT_YES=1 ;;
|
|
281
282
|
-h | --help) AGENT_SHOW_HELP=1 ;;
|
|
282
283
|
-*) log_warn "Unknown option: $arg" ;;
|
|
283
|
-
*)
|
|
284
|
+
*) positional+=("$arg") ;;
|
|
284
285
|
esac
|
|
285
286
|
done
|
|
287
|
+
if (( ! prompt_set && ${#positional[@]} )); then
|
|
288
|
+
AGENT_PROMPT="${positional[*]}"
|
|
289
|
+
fi
|
|
286
290
|
}
|
|
287
291
|
readonly AGENT_ASK_SYSTEM="You are a concise chat assistant. Reply in the SAME LANGUAGE the user writes in. Be direct and practical; use markdown, and put code in fenced blocks. <attached_file path=\"...\">...</attached_file> blocks hold real file contents (action=\"no-read\" = path only). <compacted_summary>...</compacted_summary> blocks are condensed summaries of earlier turns — treat them as ground truth."
|
|
288
292
|
|
|
@@ -846,4 +850,4 @@ agent_run_loop() {
|
|
|
846
850
|
_ems=$(agent_timer_ms)
|
|
847
851
|
echo
|
|
848
852
|
printf ' %s[context %s]%s\n' "$D_GRAY" "$(agent_context_footer "$AGENT_REPL_HISTORY" "$_ems")" "$NC"
|
|
849
|
-
}
|
|
853
|
+
}
|
|
@@ -349,7 +349,7 @@ brain_init() {
|
|
|
349
349
|
log_info "Creating private repo: ${D_CYAN}$gh_user/$repo_name${D_NC}..."
|
|
350
350
|
if gh repo create "$repo_name" --private &>/dev/null; then
|
|
351
351
|
(
|
|
352
|
-
git -C "$BRAIN_DIR" init &>/dev/null
|
|
352
|
+
git -C "$BRAIN_DIR" init -b main &>/dev/null || exit 1
|
|
353
353
|
echo "# Karnel Brain" >"$BRAIN_DIR/README.md"
|
|
354
354
|
git -C "$BRAIN_DIR" add -A
|
|
355
355
|
git -C "$BRAIN_DIR" commit -m "init brain" &>/dev/null
|
|
@@ -474,6 +474,10 @@ brain_save() {
|
|
|
474
474
|
# ── Write file ──
|
|
475
475
|
mkdir -p "$BRAIN_DIR/$category"
|
|
476
476
|
local filepath="$BRAIN_DIR/$category/${date_prefix}_${slug}.md"
|
|
477
|
+
if [[ -e "$filepath" ]]; then
|
|
478
|
+
log_error "A memory with this title already exists today: ${date_prefix}_${slug}.md"
|
|
479
|
+
return 1
|
|
480
|
+
fi
|
|
477
481
|
|
|
478
482
|
{
|
|
479
483
|
_brain_frontmatter "$title" "$tags_formatted" "$category" "$related_str"
|
|
@@ -576,6 +580,10 @@ brain_add() {
|
|
|
576
580
|
|
|
577
581
|
mkdir -p "$BRAIN_DIR/$category"
|
|
578
582
|
local filepath="$BRAIN_DIR/$category/${date_prefix}_${slug}.md"
|
|
583
|
+
if [[ -e "$filepath" ]]; then
|
|
584
|
+
log_error "A memory with this title already exists today: ${date_prefix}_${slug}.md"
|
|
585
|
+
return 1
|
|
586
|
+
fi
|
|
579
587
|
|
|
580
588
|
{
|
|
581
589
|
_brain_frontmatter "$title" "$tags_formatted" "$category" ""
|
|
@@ -928,7 +936,7 @@ brain_sync() {
|
|
|
928
936
|
local branch
|
|
929
937
|
branch=$(git -C "$BRAIN_DIR" rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
930
938
|
|
|
931
|
-
if ! git -C "$BRAIN_DIR" remote -
|
|
939
|
+
if ! git -C "$BRAIN_DIR" remote get-url origin &>/dev/null; then
|
|
932
940
|
log_info "No remote configured — local commit only"
|
|
933
941
|
list_item "Set up GitHub sync with: ${D_CYAN}karnel brain init${D_NC}"
|
|
934
942
|
separator
|
|
@@ -1231,22 +1239,18 @@ brain_edit() {
|
|
|
1231
1239
|
return 0
|
|
1232
1240
|
fi
|
|
1233
1241
|
|
|
1234
|
-
local
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
editor_bin="${editor_bin%% *}"
|
|
1238
|
-
if command -v "$editor_bin" &>/dev/null; then
|
|
1239
|
-
editor="${EDITOR:-nano}"
|
|
1240
|
-
elif [[ -z "$editor" ]] || ! command -v "$editor" &>/dev/null; then
|
|
1242
|
+
local -a editor_cmd=()
|
|
1243
|
+
read -r -a editor_cmd <<< "${EDITOR:-nano}"
|
|
1244
|
+
if ! command -v "${editor_cmd[0]}" &>/dev/null; then
|
|
1241
1245
|
for e in vim nano vi; do
|
|
1242
1246
|
if command -v "$e" &>/dev/null; then
|
|
1243
|
-
|
|
1247
|
+
editor_cmd=("$e")
|
|
1244
1248
|
break
|
|
1245
1249
|
fi
|
|
1246
1250
|
done
|
|
1247
1251
|
fi
|
|
1248
1252
|
|
|
1249
|
-
if [[ -
|
|
1253
|
+
if [[ ${#editor_cmd[@]} -eq 0 ]] || ! command -v "${editor_cmd[0]}" &>/dev/null; then
|
|
1250
1254
|
log_error "No editor found"
|
|
1251
1255
|
list_item "Install one: ${D_CYAN}karnel install editor${D_NC}"
|
|
1252
1256
|
return 1
|
|
@@ -1255,7 +1259,7 @@ brain_edit() {
|
|
|
1255
1259
|
echo
|
|
1256
1260
|
log_info "Opening: ${D_CYAN}$(_brain_title "$file")${D_NC}"
|
|
1257
1261
|
|
|
1258
|
-
"$
|
|
1262
|
+
"${editor_cmd[@]}" "$file"
|
|
1259
1263
|
|
|
1260
1264
|
log_success "Memory updated"
|
|
1261
1265
|
echo
|
|
@@ -1543,7 +1547,7 @@ EOF
|
|
|
1543
1547
|
if [[ -n "$f" ]]; then
|
|
1544
1548
|
matching_files+=("$f")
|
|
1545
1549
|
fi
|
|
1546
|
-
done < <(_brain_rg -i "$clean_query" | head -n 5 || true)
|
|
1550
|
+
done < <(_brain_rg -l -i "$clean_query" | head -n 5 || true)
|
|
1547
1551
|
|
|
1548
1552
|
if [[ ${#matching_files[@]} -eq 0 ]]; then
|
|
1549
1553
|
local -a words=($clean_query)
|
|
@@ -1562,7 +1566,7 @@ EOF
|
|
|
1562
1566
|
if [[ -n "$f" ]]; then
|
|
1563
1567
|
matching_files+=("$f")
|
|
1564
1568
|
fi
|
|
1565
|
-
done < <(_brain_rg -i -e "$word_regex" | head -n 5 || true)
|
|
1569
|
+
done < <(_brain_rg -l -i -e "$word_regex" | head -n 5 || true)
|
|
1566
1570
|
fi
|
|
1567
1571
|
fi
|
|
1568
1572
|
|
|
@@ -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
|
|
@@ -420,7 +420,11 @@ PY
|
|
|
420
420
|
ts_raw=$(echo "$session" | cut -d'|' -f2)
|
|
421
421
|
name=$(echo "$session" | cut -d'|' -f3-)
|
|
422
422
|
local escaped_name
|
|
423
|
-
escaped_name=$
|
|
423
|
+
escaped_name=${name//\\/\\\\}
|
|
424
|
+
escaped_name=${escaped_name//\"/\\\"}
|
|
425
|
+
escaped_name=${escaped_name//$'\n'/\\n}
|
|
426
|
+
escaped_name=${escaped_name//$'\r'/\\r}
|
|
427
|
+
escaped_name=${escaped_name//$'\t'/\\t}
|
|
424
428
|
if [[ $first -eq 1 ]]; then
|
|
425
429
|
first=0
|
|
426
430
|
else
|
|
@@ -514,7 +514,10 @@ pg_backup() {
|
|
|
514
514
|
log_info "Creating compressed backup for '$db_name'..."
|
|
515
515
|
local backup_dir="$KARNEL_DATA/pg_backups"
|
|
516
516
|
mkdir -p "$backup_dir"
|
|
517
|
-
local
|
|
517
|
+
local safe_db_name
|
|
518
|
+
safe_db_name=$(printf '%s' "$db_name" | tr -c '[:alnum:]_.-' '_')
|
|
519
|
+
[[ -n "$safe_db_name" ]] || { log_error "Invalid database name"; return 1; }
|
|
520
|
+
local file_name="${safe_db_name}_$(date +%Y%m%d_%H%M%S).backup.gz"
|
|
518
521
|
local file_path="$backup_dir/$file_name"
|
|
519
522
|
|
|
520
523
|
if loading "Running backup dump" _run_backup_cmd "$db_name" "$file_path"; then
|
|
@@ -522,7 +525,7 @@ pg_backup() {
|
|
|
522
525
|
log_success "Backup created successfully:"
|
|
523
526
|
list_item "$file_path"
|
|
524
527
|
list_item "Checksum generated: $(cat "${file_path}.sha256")"
|
|
525
|
-
_pg_cleanup_old_backups "$
|
|
528
|
+
_pg_cleanup_old_backups "$safe_db_name"
|
|
526
529
|
else
|
|
527
530
|
log_error "Failed to create backup"
|
|
528
531
|
rm -f "$file_path"
|
|
@@ -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"
|
|
@@ -107,7 +107,9 @@ voice_main() {
|
|
|
107
107
|
fi
|
|
108
108
|
fi
|
|
109
109
|
|
|
110
|
-
|
|
110
|
+
local -a editor_cmd=()
|
|
111
|
+
read -r -a editor_cmd <<< "${EDITOR:-nano}"
|
|
112
|
+
if ! command -v "${editor_cmd[0]}" &>/dev/null && [[ "$skip_edit" == "false" ]]; then
|
|
111
113
|
log_warn "${EDITOR:-nano} not installed — falling back to --raw mode"
|
|
112
114
|
skip_edit=true
|
|
113
115
|
fi
|
|
@@ -154,7 +156,7 @@ voice_main() {
|
|
|
154
156
|
tmpfile="$(mktemp "${TMPDIR:-${KARNEL_CACHE:-$HOME/.cache/karnel}}/karnel-XXXXXX")"
|
|
155
157
|
echo "$raw" >"$tmpfile"
|
|
156
158
|
$is_text || log_info "Review the prompt in ${EDITOR:-nano}, fix mistakes, then save and quit"
|
|
157
|
-
${
|
|
159
|
+
"${editor_cmd[@]}" "$tmpfile" </dev/tty >/dev/tty || true
|
|
158
160
|
prompt="$(< "$tmpfile")"
|
|
159
161
|
rm -f "$tmpfile"
|
|
160
162
|
elif [[ "$skip_edit" == "false" ]] && ! { [[ -t 0 ]] && [[ -t 1 ]]; }; then
|
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
|
|