karnel-termux 4.17.8 → 4.17.9

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.17.8-0078D4?style=for-the-badge" alt="Version">
11
+ <img src="https://img.shields.io/badge/version-4.17.9-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">
@@ -61,7 +61,7 @@ Core agent contributions by **devcorex**.
61
61
  ### Via checksummed GitHub release (recommended)
62
62
 
63
63
  ```bash
64
- version=4.17.8
64
+ version=4.17.9
65
65
  tmpdir=$(mktemp -d) && trap 'rm -rf "$tmpdir"' EXIT
66
66
  base="https://github.com/israelmarques1024-dotcom/karnel-termux/releases/download/v$version"
67
67
  curl -fsSL "$base/karnel-termux-install.sh" -o "$tmpdir/karnel-termux-install.sh"
package/docs/CHANGELOG.md CHANGED
@@ -1,5 +1,48 @@
1
+ ---
2
+ title: Documentation Changelog
3
+ permalink: /CHANGELOG/
4
+ ---
5
+
1
6
  # Documentation Changelog
2
7
 
8
+ ## 4.17.9
9
+
10
+ - Hardened installer and runtime security across the toolkit:
11
+ - `droid` binary install now refuses when no published SHA-256 digest is
12
+ available (fail-closed) instead of silently skipping verification.
13
+ - `keelcode` and `supabase` now extract archives through the hardened
14
+ `safe_extract_tar` (rejects symlink/absolute-path traversal) instead of
15
+ raw `tar`.
16
+ - Restored OpenCode installation: upstream publishes no checksum, so
17
+ `github_download_and_extract` warns instead of refusing (other tools that
18
+ publish checksums remain fail-closed).
19
+ - `cursor-cli` now validates the downloaded bundle is a real gzip archive
20
+ before extraction.
21
+ - Agent PLAN (read-only) mode write-guard hardened: now blocks `sed -i` /
22
+ `perl -i`, full-screen editors, and file descriptors like `2>file`.
23
+ - Agent compaction no longer drops the freshly built summary during the
24
+ trim safety-net.
25
+ - `voice` uninstall no longer removes `termux-api` unless Karnel installed it.
26
+ - `karnel show` no longer depends on `realpath` (portable fallback).
27
+ - `karnel update` reports the accurate installed version instead of a
28
+ misleading `latest`.
29
+ - Reinstall no longer deletes the ownership marker before confirming the
30
+ install, preventing a tool from being orphaned on install failure.
31
+
32
+ ## 4.17.8
33
+
34
+ - Documentation site reconciled with the GitHub Pages deployment: the `Publish
35
+ Docs` workflow (`.github/workflows/docs.yml`) builds Jekyll from `docs/` and
36
+ deploys to GitHub Pages, so the live documentation URL is
37
+ `https://israelmarques1024-dotcom.github.io/karnel-termux/`.
38
+ - `docs/CHANGELOG.md` is now a rendered page (added front matter + permalink)
39
+ and all internal links to it use the clean `/CHANGELOG/` path.
40
+ - Tool counts verified against the actual `karnel/tools/*` and
41
+ `karnel/tools/ai/*` directories: 45 AI tools, 3 editors, 8 languages,
42
+ 5 databases, 22 dev tools, 11 npm packages, 10 shell plugins, 4 UI
43
+ components, 4 deploy CLIs, 6 games, 2 network tools, 12 utility tools,
44
+ 30 security tools, 1 automation tool.
45
+
3
46
  ## 4.17.7
4
47
 
5
48
  - Documentation site overhauled: valid `_config.yml`, cayman-compatible custom
package/docs/_config.yml CHANGED
@@ -7,7 +7,7 @@ lang: en-US
7
7
  theme: jekyll-theme-cayman
8
8
  markdown: kramdown
9
9
  logo: /assets/images/karnel-logo.png
10
- custom_css: /assets/css/style.css
10
+ custom_css: /karnel-termux/assets/css/style.css
11
11
  baseurl: /karnel-termux
12
12
  show_downloads: false
13
13
  exclude:
@@ -14,6 +14,7 @@
14
14
  --karnel-text: #c9d1d9;
15
15
  --karnel-muted: #8b949e;
16
16
  --karnel-code-bg: #161b22;
17
+ color-scheme: dark light;
17
18
  }
18
19
 
19
20
  html {
@@ -37,13 +38,23 @@ body {
37
38
  }
38
39
 
39
40
  @media (prefers-color-scheme: dark) {
41
+ html {
42
+ background: var(--karnel-bg);
43
+ }
40
44
  body {
41
45
  background: var(--karnel-bg);
42
46
  color: var(--karnel-text);
43
47
  }
48
+ .main-content {
49
+ color: var(--karnel-text);
50
+ }
44
51
  .page-header {
45
52
  background-image: linear-gradient(120deg, #0078d4, #2f81f7);
46
53
  }
54
+ .page-header .project-name,
55
+ .page-header .project-tagline {
56
+ color: #ffffff;
57
+ }
47
58
  .main-content h1,
48
59
  .main-content h2,
49
60
  .main-content h3,
@@ -239,5 +239,5 @@ Regression coverage lives in `tests/smoke.sh` and verifies nested module syntax,
239
239
  the 76-entry registry, pipeline-safe parsing, mode counts, hidden GitHub workflow
240
240
  detection, scoped NestJS detection, TypeScript, and Python manifests.
241
241
 
242
- See [the 2026-07-16 changelog](../CHANGELOG.md) for the complete audit and hardening
242
+ See [the 2026-07-16 changelog](../CHANGELOG/) for the complete audit and hardening
243
243
  record.
package/docs/index.md CHANGED
@@ -11,7 +11,7 @@ Navigate the docs:
11
11
  <li><a href="./doctor/">Doctor System</a></li>
12
12
  <li><a href="./troubleshooting/">Troubleshooting</a></li>
13
13
  <li><a href="./ARCHITECTURE/">Architecture</a></li>
14
- <li><a href="./CHANGELOG.md">Changelog</a></li>
14
+ <li><a href="./CHANGELOG/">Changelog</a></li>
15
15
  <li><a href="https://israelmarques1024-dotcom.github.io/karnel-termux/">Live Site</a></li>
16
16
  </ul>
17
17
 
@@ -38,7 +38,7 @@ voice commands, and reviewed plugins — all from modules: `ai`, `auto`, `db`,
38
38
  <a href="https://github.com/israelmarques1024-dotcom/karnel-termux/blob/main/karnel/tools/utils/fconv/README.md">Utility Scripts — fconv, notes, treex, and more</a>
39
39
  <a href="./cli/#supabase--remote-project-helpers">Supabase CLI — remote-project helpers</a>
40
40
  <a href="./ARCHITECTURE/">Architecture — project structure and module system</a>
41
- <a href="./CHANGELOG.md">Changelog — version history and fixes</a>
41
+ <a href="./CHANGELOG/">Changelog — version history and fixes</a>
42
42
  </div>
43
43
 
44
44
  ## Credits
@@ -43,12 +43,21 @@ npm publish does not block the release. The workflow needs `contents: write`
43
43
  permission (already declared). If `gh release create` fails, confirm the tag
44
44
  exists and the token used by GitHub Actions has write access.
45
45
 
46
- ## Vercel deployment
47
-
48
- The live site deploys automatically through the Vercel integration on push to
49
- `main`; no GitHub Actions workflow is required. If a deploy fails, check the
50
- Vercel dashboard for build logs and confirm the framework preset, install
51
- command, and environment variables.
46
+ ## Documentation site (GitHub Pages)
47
+
48
+ The documentation site is a Jekyll (cayman theme) site built from the `docs/`
49
+ directory and published to GitHub Pages by the `Publish Docs` workflow
50
+ (`.github/workflows/docs.yml`) on every push to `main` that changes `docs/**`.
51
+ The workflow runs `actions/jekyll-build-pages` (from `docs/`, output to
52
+ `docs/_site`), uploads the result as a Pages artifact, and deploys it to the
53
+ `github-pages` environment. The live site is
54
+ `https://israelmarques1024-dotcom.github.io/karnel-termux/`.
55
+
56
+ If a build fails, open the Actions run for the failing job and read the Jekyll
57
+ output: the usual causes are invalid `_config.yml` YAML, an SCSS compile error
58
+ in `assets/css/style.scss`, or a malformed `{{ }}` Liquid tag. After a
59
+ successful deploy, the published site is visible under the repository's
60
+ **Settings → Pages**.
52
61
 
53
62
  ## Reporting a bug
54
63
 
@@ -1 +1 @@
1
- ad787cd9d5efa67b498b0b1dc5e00203553b32e7
1
+ f3ce43f67dd4d213f0af574d1673e8dbd6c910b9
@@ -86,8 +86,15 @@ show_main() {
86
86
  return
87
87
  fi
88
88
 
89
- local readme_path
90
- readme_path="$(realpath "$KARNEL_PATH/tools/$module/$tool/README.md" 2>/dev/null)"
89
+ local readme_path raw
90
+ raw="$KARNEL_PATH/tools/$module/$tool/README.md"
91
+ if command -v realpath &>/dev/null; then
92
+ readme_path="$(realpath "$raw" 2>/dev/null)"
93
+ elif command -v readlink &>/dev/null; then
94
+ readme_path="$(readlink -f "$raw" 2>/dev/null)"
95
+ else
96
+ readme_path="$raw"
97
+ fi
91
98
 
92
99
  if [[ -z "$readme_path" ]]; then
93
100
  log_error "No documentation found for $module/$tool"
@@ -347,12 +347,22 @@ _update_try_git() {
347
347
  return 1
348
348
  }
349
349
 
350
+ _npm_installed_version() {
351
+ local v pr
352
+ v=$(npm list -g karnel-termux 2>/dev/null | grep -oP 'karnel-termux@\K[0-9.]+')
353
+ if [[ -z "$v" ]]; then
354
+ pr="$(npm root -g 2>/dev/null)/karnel-termux/package.json"
355
+ [[ -f "$pr" ]] && v=$(grep -oP '"version"\s*:\s*"\K[0-9.]+' "$pr")
356
+ fi
357
+ printf '%s' "${v:-unknown}"
358
+ }
359
+
350
360
  _update_try_npm() {
351
361
  command -v npm &>/dev/null || return 1
352
362
  log_info "Trying npm update..."
353
363
  if npm update -g karnel-termux --ignore-scripts 2>/dev/null; then
354
364
  local new_ver
355
- new_ver=$(npm list -g karnel-termux 2>/dev/null | grep karnel-termux | grep -oP '@\K[0-9.]+' || echo "latest")
365
+ new_ver=$(_npm_installed_version)
356
366
  log_success "Updated to v$new_ver via npm"
357
367
  return 0
358
368
  fi
@@ -365,7 +375,7 @@ _update_try_npm_install() {
365
375
  log_info "Trying npm install..."
366
376
  if npm install -g karnel-termux@latest --ignore-scripts 2>/dev/null; then
367
377
  local new_ver
368
- new_ver=$(npm list -g karnel-termux 2>/dev/null | grep karnel-termux | grep -oP '@\K[0-9.]+' || echo "latest")
378
+ new_ver=$(_npm_installed_version)
369
379
  log_success "Updated to v$new_ver via npm install"
370
380
  return 0
371
381
  fi
@@ -129,11 +129,18 @@ _download_cursor_binary_impl() {
129
129
 
130
130
  # Cursor does not publish a verifiable checksum for this asset, so integrity
131
131
  # relies on HTTPS transport only; upstream does not publish a verifiable checksum.
132
+ # Validate the payload is a real gzip archive before extracting so a corrupted
133
+ # or error response (e.g. an HTML error page) is rejected.
132
134
  if ! curl -fsSL "$download_url" -o "$staging_dir/$tarball" &>>"$LOG_FILE"; then
133
135
  rm -rf "$staging_dir"
134
136
  log_error "Failed to download Cursor CLI binary"
135
137
  return 1
136
138
  fi
139
+ if ! gzip -t "$staging_dir/$tarball" 2>/dev/null; then
140
+ rm -rf "$staging_dir"
141
+ log_error "Downloaded Cursor bundle is not a valid gzip archive"
142
+ return 1
143
+ fi
137
144
 
138
145
  if ! tar -zxf "$staging_dir/$tarball" --strip-components=1 -C "$staging_dir" &>>"$LOG_FILE"; then
139
146
  rm -rf "$staging_dir"
@@ -125,13 +125,22 @@ _download_droid_binary_impl() {
125
125
 
126
126
  local expected actual
127
127
  expected="$(curl -fsSL "$sha_url" 2>/dev/null | awk '{print $1}')"
128
- if [ -n "$expected" ] && command -v sha256sum &>/dev/null; then
128
+ if [[ ! "$expected" =~ ^[0-9a-f]{64}$ ]]; then
129
+ log_error "No published SHA-256 for Droid binary; refusing install"
130
+ rm -f "$DROID_DATA_DIR/droid"
131
+ return 1
132
+ fi
133
+ if command -v sha256sum &>/dev/null; then
129
134
  actual="$(sha256sum "$DROID_DATA_DIR/droid" | awk '{print $1}')"
130
135
  if [ "$actual" != "$expected" ]; then
131
136
  log_error "Checksum verification failed"
132
137
  rm -f "$DROID_DATA_DIR/droid"
133
138
  return 1
134
139
  fi
140
+ else
141
+ log_error "sha256sum unavailable; refusing install"
142
+ rm -f "$DROID_DATA_DIR/droid"
143
+ return 1
135
144
  fi
136
145
 
137
146
  chmod +x "$DROID_DATA_DIR/droid"
@@ -2,6 +2,7 @@
2
2
 
3
3
  import "@/utils/log"
4
4
  import "@/utils/version"
5
+ import "@/utils/install"
5
6
 
6
7
  if ! declare -f safe_extract_tar >/dev/null 2>&1; then
7
8
  safe_extract_tar() {
@@ -2,6 +2,14 @@
2
2
 
3
3
  import "@/utils/log"
4
4
  import "@/utils/version"
5
+ import "@/utils/install"
6
+
7
+ if ! declare -f safe_extract_tar >/dev/null 2>&1; then
8
+ safe_extract_tar() {
9
+ local archive="$1" outdir="$2" strip_components="${3:-0}"
10
+ tar -xzf "$archive" -C "$outdir" --strip-components="$strip_components"
11
+ }
12
+ fi
5
13
 
6
14
  _SUPABASE_VERSION="2.20.8"
7
15
  _SUPABASE_RELEASE_URL="https://github.com/supabase/cli/releases/download/v${_SUPABASE_VERSION}"
@@ -81,8 +89,11 @@ install_supabase() (
81
89
  fi
82
90
  log_success "Checksum verified"
83
91
 
84
- # Extract
85
- tar -xzf "$tmp_dir/$filename" -C "$tmp_dir" supabase 2>/dev/null
92
+ # Extract (hardened: rejects symlink/absolute-path traversal)
93
+ safe_extract_tar "$tmp_dir/$filename" "$tmp_dir" || {
94
+ log_error "Extraction failed"
95
+ return 1
96
+ }
86
97
  if [[ ! -f "$tmp_dir/supabase" ]]; then
87
98
  log_error "Extraction failed"
88
99
  return 1
@@ -3,13 +3,20 @@
3
3
  import "@/utils/log"
4
4
 
5
5
  _uninstall_voice_tool() {
6
+ local karnel_data="${KARNEL_DATA:-${XDG_DATA_HOME:-$HOME/.local/share}/karnel-data}"
7
+ local marker="$karnel_data/voice/.termux-api-managed"
6
8
  if command -v termux-api &>/dev/null; then
7
- log_info "Removing Termux:API..."
8
- if ! pkg uninstall -y termux-api &>>"$LOG_FILE"; then
9
- log_error "Failed to remove Termux:API (see $LOG_FILE)"
10
- return 1
9
+ if [[ -f "$marker" ]]; then
10
+ log_info "Removing Termux:API (installed by Karnel)..."
11
+ if ! pkg uninstall -y termux-api &>>"$LOG_FILE"; then
12
+ log_error "Failed to remove Termux:API (see $LOG_FILE)"
13
+ return 1
14
+ fi
15
+ rm -f "$marker"
16
+ log_success "Termux:API removed"
17
+ else
18
+ log_info "Termux:API is present but was not installed by Karnel; leaving it in place"
11
19
  fi
12
- log_success "Termux:API removed"
13
20
  else
14
21
  log_info "Termux:API is not installed"
15
22
  fi
@@ -481,14 +481,22 @@ _agent_exec_to_file() {
481
481
  # ------------------------------------------------------------
482
482
  _agent_cmd_is_write() {
483
483
  local cmd="$1"
484
- # file redirections (2>&1 / >= are not redirections to a file)
485
- if printf '%s\n' "$cmd" | grep -qE '(^|[;&|[:space:]])(>|>>)[^=&]'; then
484
+ # file redirections: >file >>file 2>file 1>>file &>file (excludes fd-to-fd like >&2 and comparisons >=)
485
+ if printf '%s\n' "$cmd" | grep -qE '(^|[;&|[:space:]])(>|>>|&>|[0-9]>|[0-9]>>)([^&=]|$)'; then
486
486
  return 0
487
487
  fi
488
488
  # command substitution / backticks execute arbitrary code → write
489
489
  if printf '%s\n' "$cmd" | grep -qE '\$\(|`'; then
490
490
  return 0
491
491
  fi
492
+ # in-place editors: sed -i / perl -i modify files in place
493
+ if printf '%s\n' "$cmd" | grep -qiE '(^|[;&|[:space:]])(sed|perl)[[:space:]][^|;&]*-[A-Za-z]*i[A-Za-z]*([[:space:]]|$)'; then
494
+ return 0
495
+ fi
496
+ # full-screen / line editors that can modify files
497
+ if printf '%s\n' "$cmd" | grep -qiE '(^|[;&|[:space:]])(vim|nvim|emacs|ed|ex|vi|nano)[[:space:]]'; then
498
+ return 0
499
+ fi
492
500
  # blocklist of commands that write to disk / change state / spawn a shell
493
501
  printf '%s\n' "$cmd" | grep -qiE '(^|[;&|[:space:]])(rm|rmdir|unlink|mv|cp|mkdir|touch|ln|chmod|chown|chgrp|install|truncate|tee|dd|mkfs|mount|umount|tar|gzip|gunzip|bzip2|xz|zstd|curl|wget|python3|python|node|npm|bun|yarn|pnpm|cargo|go |rustc|git (add|commit|push|pull|merge|rebase|reset|checkout|switch|restore|clean|stash|tag|clone|init|rm|mv)|pkg (install|uninstall|upgrade|reinstall|update)|apt( |-)|apt-get|dpkg|yum|dnf|pacman|brew|pip|pip3|uv|conda|mysql|psql|sqlite3|redis-cli|mongosh|kill|pkill|killall|service|systemctl|halt|reboot|shutdown|sudo|doas|su|pkexec|chroot|bash|sh|dash|zsh|ksh|eval|source|exec|screen|tmux|ssh|scp|sftp|rsync|telnet|nc|ncat|ftp|lftp|rsh|sshpass|socat|crontab|at |iptables|nft|ufw|docker|podman|kubectl|helm)[[:space:]]' && return 0
494
502
  return 1
@@ -1359,12 +1367,17 @@ agent_context_footer() {
1359
1367
  agent_history_trim_tokens() {
1360
1368
  local history="$1" budget="${2:-0}"
1361
1369
  (( budget <= 0 )) && { echo "$history"; return; }
1362
- local toks n
1370
+ local toks n drop_idx is_summary
1363
1371
  while :; do
1364
1372
  toks=$(agent_context_tokens "$history")
1365
1373
  (( toks <= budget )) && break
1366
1374
  n=$(printf '%s' "$history" | jq 'length')
1367
1375
  (( n <= 4 )) && break
1376
+ drop_idx=$(printf '%s' "$history" | jq -c 'if .[0].role == "system" then 1 else 0 end')
1377
+ is_summary=$(printf '%s' "$history" | jq -r --argjson i "$drop_idx" '.[$i].content // "" | contains("<compacted_summary>")')
1378
+ if [[ "$is_summary" == "true" ]]; then
1379
+ break
1380
+ fi
1368
1381
  history=$(printf '%s' "$history" | jq -c 'if .[0].role == "system" then .[0:1] + .[2:] else .[1:] end')
1369
1382
  done
1370
1383
  echo "$history"
@@ -291,9 +291,7 @@ github_download_and_extract() {
291
291
  if [[ "$expected" =~ ^[0-9a-f]{64}$ ]]; then
292
292
  verify_sha256 "$tarball" "$expected" || return 1
293
293
  else
294
- log_error "No verifiable SHA-256 digest published for $repo/$asset; refusing install"
295
- rm -f "$tarball"
296
- return 1
294
+ log_warn "No published SHA-256 digest for $repo/$asset; skipping integrity verification"
297
295
  fi
298
296
  extract_tarball "$tarball" "$outdir" || return 1
299
297
  return 0
@@ -60,9 +60,6 @@ _run_tool_lifecycle_action() {
60
60
  "$uninstall_handler"
61
61
  rc=$?
62
62
  (( rc == 0 )) || return "$rc"
63
- if (( protected )); then
64
- rm -f "$marker" || return 1
65
- fi
66
63
  "$install_handler"
67
64
  rc=$?
68
65
  if (( rc == 0 && protected )); then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "karnel-termux",
3
- "version": "4.17.8",
3
+ "version": "4.17.9",
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"