karnel-termux 4.18.2 → 4.18.3
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 +2 -2
- package/docs/CHANGELOG.md +8 -0
- package/karnel/RELEASE_COMMIT +1 -1
- package/karnel/cli/karnel.sh +17 -1
- package/karnel/tools/ai/all.sh +7 -0
- package/karnel/tools/ai/freebuff/install.sh +21 -0
- package/karnel/utils/compat.sh +56 -7
- 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/karnel-termuxOFC/karnel-termux">
|
|
11
|
-
<img src="https://img.shields.io/badge/version-4.18.
|
|
11
|
+
<img src="https://img.shields.io/badge/version-4.18.3-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.18.
|
|
81
|
+
version=4.18.3
|
|
82
82
|
tmpdir=$(mktemp -d) && trap 'rm -rf "$tmpdir"' EXIT
|
|
83
83
|
base="https://github.com/karnel-termuxOFC/karnel-termux/releases/download/v$version"
|
|
84
84
|
curl -fsSL "$base/karnel-termux-install.sh" -o "$tmpdir/karnel-termux-install.sh"
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ layout: base
|
|
|
6
6
|
|
|
7
7
|
# Documentation Changelog
|
|
8
8
|
|
|
9
|
+
## 4.18.3
|
|
10
|
+
|
|
11
|
+
- **Every command that installs something now adapts what it put on PATH.** The dispatcher brackets `install`, `update`, `upgrade`, `reinstall`, `restore`, `plugin`, `supabase`, `deploy`, `voice`, `robin`, `pg`, `open` and `init` with a snapshot of the writable parts of PATH (`path|size|mtime` per entry) and afterwards adapts exactly the entries that appeared or changed. That closes the gap the registries could never close: an installer that never calls the compatibility layer, one that names a command its registry does not mention, and a file restored from an archive with its original timestamp all end up wrapped anyway. Sweeping the prefix instead was measured on this device at 51 seconds of `readelf` over 800 entries (and 875 seconds with `readelf -l`); diffing a snapshot takes 60 ms and touches nothing the command did not write. The exit code of the command is taken before adaptation and returned unchanged.
|
|
12
|
+
- **The AI reinstall fallback adapts what it installed.** `_run_ai_tool_action` called `$install_fn` and returned without passing through its adapt call, so those binaries stayed unwrapped.
|
|
13
|
+
- **An install can no longer report success for a command that does not start.** A device audit of all 169 catalogued tools found 21 installed and 147 absent — and exactly one of them dead: `$PREFIX/bin/freebuff` had been left as npm's shim, which exits 1 on Termux with "Unsupported platform: android arm64", while `karnel install ai --freebuff` still reported "already installed". Both paths of `install_freebuff` now prove the entry runs before returning, the same way `_fix_freebuff_runtime` already proves the runtime does. The audit is green afterwards: freebuff `0.2.22`, bun `1.4.2`, supabase `2.20.8`, zero broken.
|
|
14
|
+
- **The compatibility suite is part of the test run.** `tests/android-compat.sh` had never been listed in `tests/run.sh`, so its cases only ever ran by hand; it now runs in `npm test` and in CI, and every other file under `tests/` was checked against the list while adding it.
|
|
15
|
+
- **Tests.** Five new cases in `tests/android-compat.sh` (a binary created during a command, a binary rewritten in place, only the entries that changed, an exit code that cannot change, and the dispatcher wiring itself) plus two in `tests/ai-installer-hardening.sh` (a dead freebuff entry fails, a live one is accepted), taking the suites to 28 and 11 cases. Every branch was proven to fail first: dropping the adapt call fails 1 case, dropping the snapshot fails 1, making `compat_adapt_since` a no-op fails 2, removing the AI fallback's adapt fails 1, removing the already-installed verification fails 1, and turning that verification into a no-op fails both new freebuff cases.
|
|
16
|
+
|
|
9
17
|
## 4.18.2
|
|
10
18
|
|
|
11
19
|
- **Wrappers no longer hand a preload to glibc.** `login(1)` exports `LD_PRELOAD=$PREFIX/lib/libtermux-exec-ld-preload.so`, a bionic object; glibc's `ld.so` cannot load it, so every wrapped tool died before `main()` with `.../glibc/lib/libc.so: invalid ELF header`. Tier 3's own preload was fatal in the other direction: exporting the glibc `libtermux-exec.so` shim left every bionic child of the tool failing with `library "libc.so.6" not found`. Every wrapper now starts with `unset LD_PRELOAD`, and tier 3 exports `PATH` only.
|
package/karnel/RELEASE_COMMIT
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
4f1840c76ffba58dde286b506142fa1f9e5ee1d8
|
package/karnel/cli/karnel.sh
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import "@/utils/log"
|
|
4
4
|
import "@/utils/colors"
|
|
5
|
+
import "@/utils/compat"
|
|
5
6
|
|
|
6
7
|
: "${KARNEL_VERSION:=unknown}"
|
|
7
8
|
|
|
@@ -67,8 +68,23 @@ _karnel_dispatch() {
|
|
|
67
68
|
|
|
68
69
|
if [[ -f "$command_file" ]]; then
|
|
69
70
|
import "@/cli/commands/$cmd"
|
|
71
|
+
# Every command that can put a binary on PATH is bracketed by a snapshot
|
|
72
|
+
# of PATH, and whatever changed inside it is adapted afterwards. That is
|
|
73
|
+
# what makes the layer cover *all* tools: an installer that never calls
|
|
74
|
+
# compat itself, one that names a command its registry does not mention,
|
|
75
|
+
# and one that restores a file from an archive all end up here anyway.
|
|
76
|
+
local compat_snap=""
|
|
77
|
+
case "$cmd" in
|
|
78
|
+
install | update | upgrade | reinstall | restore | plugin | supabase | deploy | voice | robin | pg | open | init)
|
|
79
|
+
compat_snap="$(compat_path_snapshot 2>/dev/null)" || compat_snap=""
|
|
80
|
+
;;
|
|
81
|
+
esac
|
|
70
82
|
"${cmd}_main" "$@"
|
|
71
|
-
|
|
83
|
+
local cmd_rc=$?
|
|
84
|
+
if [[ -n "$compat_snap" ]]; then
|
|
85
|
+
compat_adapt_since "$compat_snap" || true
|
|
86
|
+
fi
|
|
87
|
+
return "$cmd_rc"
|
|
72
88
|
fi
|
|
73
89
|
|
|
74
90
|
import "@/tools/plugins/install"
|
package/karnel/tools/ai/all.sh
CHANGED
|
@@ -230,6 +230,13 @@ _run_ai_tool_action() {
|
|
|
230
230
|
return "$uninstall_rc"
|
|
231
231
|
fi
|
|
232
232
|
"$install_fn"
|
|
233
|
+
local install_rc=$?
|
|
234
|
+
# The fallback path never passes through _run_ai_tool_action's adapt call,
|
|
235
|
+
# so the binaries this install just wrote would stay unwrapped.
|
|
236
|
+
if ((install_rc == 0)); then
|
|
237
|
+
_ai_tool_compat_adapt "$id"
|
|
238
|
+
fi
|
|
239
|
+
return "$install_rc"
|
|
233
240
|
}
|
|
234
241
|
|
|
235
242
|
_all_ai_tools_action() {
|
|
@@ -23,6 +23,7 @@ install_freebuff() {
|
|
|
23
23
|
log_info "Freebuff is already installed"
|
|
24
24
|
_fix_freebuff_runtime || true
|
|
25
25
|
_install_freebuff_entry || true
|
|
26
|
+
_verify_freebuff_entry || return 1
|
|
26
27
|
return 2
|
|
27
28
|
fi
|
|
28
29
|
|
|
@@ -42,6 +43,7 @@ install_freebuff() {
|
|
|
42
43
|
_fix_freebuff_shebang || return 1
|
|
43
44
|
_fix_freebuff_runtime || return 1
|
|
44
45
|
_install_freebuff_entry || return 1
|
|
46
|
+
_verify_freebuff_entry || return 1
|
|
45
47
|
log_success "Freebuff installed"
|
|
46
48
|
}
|
|
47
49
|
|
|
@@ -96,6 +98,25 @@ _freebuff_binary_runs() {
|
|
|
96
98
|
((rc == 0))
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
# npm recreates its shim at $PREFIX/bin/freebuff on every global operation, and
|
|
102
|
+
# that shim cannot start on Android - so an install can look successful while
|
|
103
|
+
# the command itself is dead. Every path therefore proves the entry runs before
|
|
104
|
+
# reporting success, the same way _fix_freebuff_runtime proves the runtime does.
|
|
105
|
+
_verify_freebuff_entry() {
|
|
106
|
+
local entry rc=0
|
|
107
|
+
entry="$(command -v freebuff 2>/dev/null)"
|
|
108
|
+
if [[ -z "$entry" || ! -e "$entry" ]]; then
|
|
109
|
+
log_error "Freebuff is not on PATH after install"
|
|
110
|
+
return 1
|
|
111
|
+
fi
|
|
112
|
+
{ timeout 30 "$entry" --version >/dev/null 2>&1; rc=$?; } 2>/dev/null
|
|
113
|
+
if ((rc != 0)); then
|
|
114
|
+
log_error "Freebuff does not run after install (exit $rc)"
|
|
115
|
+
return 1
|
|
116
|
+
fi
|
|
117
|
+
return 0
|
|
118
|
+
}
|
|
119
|
+
|
|
99
120
|
_freebuff_target_key() {
|
|
100
121
|
case "$(uname -m)" in
|
|
101
122
|
aarch64 | arm64) printf 'linux-arm64\n' ;;
|
package/karnel/utils/compat.sh
CHANGED
|
@@ -534,13 +534,11 @@ compat_fix_shebangs() {
|
|
|
534
534
|
printf '%s\n' "$fixed"
|
|
535
535
|
}
|
|
536
536
|
|
|
537
|
-
# Adapts
|
|
538
|
-
#
|
|
539
|
-
#
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
local tool="$1" path real
|
|
543
|
-
path="$(command -v -- "$tool" 2>/dev/null)" || return 0
|
|
537
|
+
# Adapts one resolved path. Wraps a glibc ELF so the kernel can start it;
|
|
538
|
+
# leaves native binaries, scripts and text files alone. Always returns 0:
|
|
539
|
+
# adaptation is an optimisation, never a reason to fail an install.
|
|
540
|
+
_compat_adapt_path() {
|
|
541
|
+
local path="$1" real
|
|
544
542
|
[[ -n "$path" ]] || return 0
|
|
545
543
|
real="$(readlink -f -- "$path" 2>/dev/null || printf '%s' "$path")"
|
|
546
544
|
[[ -f "$real" && -x "$real" ]] || return 0
|
|
@@ -560,6 +558,57 @@ compat_adapt_installed() {
|
|
|
560
558
|
return 0
|
|
561
559
|
}
|
|
562
560
|
|
|
561
|
+
# Adapts whatever a tool has just put on PATH.
|
|
562
|
+
compat_adapt_installed() {
|
|
563
|
+
local tool="$1" path
|
|
564
|
+
path="$(command -v -- "$tool" 2>/dev/null)" || return 0
|
|
565
|
+
[[ -n "$path" ]] || return 0
|
|
566
|
+
_compat_adapt_path "$path"
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
# Records every direct entry of the writable parts of PATH as
|
|
570
|
+
# "path|size|mtime", printed to a temporary file. Taken before a command runs
|
|
571
|
+
# so the layer can afterwards adapt exactly what that command touched.
|
|
572
|
+
#
|
|
573
|
+
# Sweeping the whole prefix instead would need readelf on every ELF, which
|
|
574
|
+
# measures 60+ seconds over a Termux bin directory of 800 entries; diffing a
|
|
575
|
+
# snapshot adapts only the handful of files that actually changed. It also
|
|
576
|
+
# means no installer has to declare its binary names: a tool that installs a
|
|
577
|
+
# command its registry does not mention is still covered, and a file restored
|
|
578
|
+
# from an archive with its original mtime is caught by being a new path.
|
|
579
|
+
compat_path_snapshot() {
|
|
580
|
+
local dir tmp
|
|
581
|
+
tmp="$(mktemp "${TMPDIR:-${KARNEL_CACHE:-/tmp}}/karnel-compat-snap.XXXXXX" 2>/dev/null)" || return 1
|
|
582
|
+
local IFS=':'
|
|
583
|
+
for dir in $PATH; do
|
|
584
|
+
[[ -n "$dir" && -d "$dir" && -w "$dir" ]] || continue
|
|
585
|
+
find "$dir" -maxdepth 1 \( -type f -o -type l \) -printf '%p|%s|%T@\n' 2>/dev/null || true
|
|
586
|
+
done | sort >"$tmp" || true
|
|
587
|
+
printf '%s\n' "$tmp"
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
# Adapts every PATH entry that appeared or changed since a snapshot, then
|
|
591
|
+
# removes both files. Returns 0 unconditionally.
|
|
592
|
+
compat_adapt_since() {
|
|
593
|
+
local snap="$1" tmp dir path
|
|
594
|
+
[[ -f "$snap" ]] || return 0
|
|
595
|
+
tmp="$(mktemp "${TMPDIR:-${KARNEL_CACHE:-/tmp}}/karnel-compat-now.XXXXXX" 2>/dev/null)" || {
|
|
596
|
+
rm -f -- "$snap"
|
|
597
|
+
return 0
|
|
598
|
+
}
|
|
599
|
+
local IFS=':'
|
|
600
|
+
for dir in $PATH; do
|
|
601
|
+
[[ -n "$dir" && -d "$dir" && -w "$dir" ]] || continue
|
|
602
|
+
find "$dir" -maxdepth 1 \( -type f -o -type l \) -printf '%p|%s|%T@\n' 2>/dev/null || true
|
|
603
|
+
done | sort >"$tmp" || true
|
|
604
|
+
while IFS= read -r path; do
|
|
605
|
+
[[ -n "$path" ]] || continue
|
|
606
|
+
_compat_adapt_path "$path" || true
|
|
607
|
+
done < <(comm -13 -- "$snap" "$tmp" 2>/dev/null | cut -d'|' -f1)
|
|
608
|
+
rm -f -- "$snap" "$tmp"
|
|
609
|
+
return 0
|
|
610
|
+
}
|
|
611
|
+
|
|
563
612
|
# Human-readable one-liner for doctor output.
|
|
564
613
|
compat_describe() {
|
|
565
614
|
local file="$1" kind interp real
|
package/package.json
CHANGED