karnel-termux 4.7.6 → 4.7.7

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.
Files changed (81) hide show
  1. package/README.md +230 -225
  2. package/install.sh +30 -9
  3. package/karnel/bin/karnel +2 -2
  4. package/karnel/cli/commands/backup.sh +10 -2
  5. package/karnel/cli/commands/brain.sh +28 -23
  6. package/karnel/cli/commands/cleanup.sh +10 -4
  7. package/karnel/cli/commands/deploy.sh +53 -0
  8. package/karnel/cli/commands/doctor/code.sh +225 -0
  9. package/karnel/cli/commands/doctor/code_detect.sh +184 -0
  10. package/karnel/cli/commands/doctor/code_exec.sh +278 -0
  11. package/karnel/cli/commands/doctor/code_langs.sh +229 -0
  12. package/karnel/cli/commands/doctor/fixes.sh +63 -46
  13. package/karnel/cli/commands/doctor.sh +222 -80
  14. package/karnel/cli/commands/env.sh +2 -0
  15. package/karnel/cli/commands/ia.sh +12 -2
  16. package/karnel/cli/commands/init.sh +17 -9
  17. package/karnel/cli/commands/install.sh +90 -54
  18. package/karnel/cli/commands/list.sh +36 -0
  19. package/karnel/cli/commands/pg.sh +21 -6
  20. package/karnel/cli/commands/reinstall.sh +99 -0
  21. package/karnel/cli/commands/restore.sh +43 -3
  22. package/karnel/cli/commands/search.sh +2 -2
  23. package/karnel/cli/commands/update.sh +6 -1
  24. package/karnel/cli/commands/upgrade.sh +8 -1
  25. package/karnel/cli/commands/voice.sh +2 -1
  26. package/karnel/cli/karnel.sh +11 -5
  27. package/karnel/modules/games.sh +11 -0
  28. package/karnel/tools/ai/all.sh +1 -0
  29. package/karnel/tools/ai/copilot-termux/README.md +40 -0
  30. package/karnel/tools/ai/copilot-termux/install.sh +80 -0
  31. package/karnel/tools/ai/copilot-termux/package.json +20 -0
  32. package/karnel/tools/db/all.sh +2 -0
  33. package/karnel/tools/deploy/railway/install.sh +2 -2
  34. package/karnel/tools/dev/all.sh +8 -0
  35. package/karnel/tools/dev/applaunch/__pycache__/applaunch.cpython-314.pyc +0 -0
  36. package/karnel/tools/dev/applaunch/applaunch.py +434 -0
  37. package/karnel/tools/dev/applaunch/install.sh +51 -0
  38. package/karnel/tools/dev/fconv/__pycache__/fconv.cpython-314.pyc +0 -0
  39. package/karnel/tools/dev/fconv/fconv.py +749 -0
  40. package/karnel/tools/dev/fconv/install.sh +51 -0
  41. package/karnel/tools/dev/filecheck/__pycache__/filecheck.cpython-314.pyc +0 -0
  42. package/karnel/tools/dev/filecheck/filecheck.py +429 -0
  43. package/karnel/tools/dev/filecheck/install.sh +51 -0
  44. package/karnel/tools/dev/notes/__pycache__/notes.cpython-314.pyc +0 -0
  45. package/karnel/tools/dev/notes/install.sh +51 -0
  46. package/karnel/tools/dev/notes/notes.py +849 -0
  47. package/karnel/tools/dev/passman/__pycache__/passman.cpython-314.pyc +0 -0
  48. package/karnel/tools/dev/passman/install.sh +51 -0
  49. package/karnel/tools/dev/passman/passman.py +536 -0
  50. package/karnel/tools/dev/splash/__pycache__/splash.cpython-314.pyc +0 -0
  51. package/karnel/tools/dev/splash/install.sh +51 -0
  52. package/karnel/tools/dev/splash/splash.py +188 -0
  53. package/karnel/tools/dev/treex/install.sh +51 -0
  54. package/karnel/tools/dev/treex/treex.py +2036 -0
  55. package/karnel/tools/dev/websites/__pycache__/websites.cpython-314.pyc +0 -0
  56. package/karnel/tools/dev/websites/install.sh +51 -0
  57. package/karnel/tools/dev/websites/websites.py +844 -0
  58. package/karnel/tools/games/all.sh +62 -0
  59. package/karnel/tools/games/arcade/__pycache__/arcade.cpython-314.pyc +0 -0
  60. package/karnel/tools/games/arcade/arcade.py +193 -0
  61. package/karnel/tools/games/arcade/install.sh +51 -0
  62. package/karnel/tools/games/buzz/__pycache__/buzz.cpython-314.pyc +0 -0
  63. package/karnel/tools/games/buzz/buzz.py +1264 -0
  64. package/karnel/tools/games/buzz/install.sh +51 -0
  65. package/karnel/tools/games/ctfgod/__pycache__/ctfgod.cpython-314.pyc +0 -0
  66. package/karnel/tools/games/ctfgod/ctfgod.py +1576 -0
  67. package/karnel/tools/games/ctfgod/install.sh +51 -0
  68. package/karnel/tools/games/detective/__pycache__/detective.cpython-314.pyc +0 -0
  69. package/karnel/tools/games/detective/detective.py +2091 -0
  70. package/karnel/tools/games/detective/install.sh +51 -0
  71. package/karnel/tools/games/pet-friends/__pycache__/pet-friends.cpython-314.pyc +0 -0
  72. package/karnel/tools/games/pet-friends/install.sh +51 -0
  73. package/karnel/tools/games/pet-friends/pet-friends.py +15802 -0
  74. package/karnel/tools/games/tamagotchi/__pycache__/tamagotchi.cpython-314.pyc +0 -0
  75. package/karnel/tools/games/tamagotchi/install.sh +51 -0
  76. package/karnel/tools/games/tamagotchi/tamagotchi.py +1224 -0
  77. package/karnel/tools/games/terminal-arcade/__pycache__/terminal-arcade.cpython-314.pyc +0 -0
  78. package/karnel/tools/games/terminal-arcade/terminal-arcade.py +193 -0
  79. package/karnel/tools/npm/all.sh +1 -0
  80. package/karnel/utils/log.sh +34 -12
  81. package/package.json +1 -1
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Project detection engine for karnel doctor code
4
+ # Analyzes directory structure and identifies languages/frameworks
5
+
6
+ _detect_project() {
7
+ local dir="${1:-.}"
8
+ dir="$(cd "$dir" 2>/dev/null && pwd)" || { log_error "Directory not found: $dir"; return 1; }
9
+
10
+ PROJECT_LANGS=()
11
+ PROJECT_FRAMEWORKS=()
12
+ PROJECT_MANIFESTS=()
13
+ PROJECT_SUBDIRS=()
14
+ _scan_project "$dir" 0 4 "$dir"
15
+ }
16
+
17
+ _scan_project() {
18
+ local current="$1" depth="$2" max_depth="$3" root_dir="${4:-$1}"
19
+ (( depth > max_depth )) && return
20
+
21
+ local dir_langs=()
22
+ local dir_fws=()
23
+ local dir_manifests=()
24
+
25
+ for entry in "$current"/* "$current"/.github "$current"/.luacheckrc; do
26
+ [[ -e "$entry" ]] || continue
27
+ [[ -L "$entry" ]] && continue
28
+ local name; name=$(basename "$entry")
29
+ case "$name" in
30
+ node_modules|.git|.venv|venv|__pycache__|target|dist|build|vendor|coverage|.cache|.terraform|.next|.nuxt|.angular|cache|elixir_build|_build|deps|.bundle|.gem|bin|obj|.gradle|.mvn|CMakeFiles|.cargo|.rustup|go/pkg|Godeps)
31
+ continue ;;
32
+ esac
33
+
34
+ if [[ -f "$entry" ]]; then
35
+ _check_manifest "$name" "$entry" dir_langs dir_fws dir_manifests
36
+ elif [[ -d "$entry" ]]; then
37
+ _scan_project "$entry" $((depth + 1)) "$max_depth" "$root_dir"
38
+ fi
39
+ done
40
+
41
+ if [[ ${#dir_langs[@]} -gt 0 ]]; then
42
+ for lang in "${dir_langs[@]}"; do PROJECT_LANGS+=("$lang"); done
43
+ for fw in "${dir_fws[@]}"; do PROJECT_FRAMEWORKS+=("$fw"); done
44
+ for mf in "${dir_manifests[@]}"; do PROJECT_MANIFESTS+=("$mf"); done
45
+
46
+ # Register subproject if deeper than root
47
+ if (( depth > 0 )) && [[ "$current" != "$root_dir" ]]; then
48
+ local rel; rel="${current#"$root_dir"/}"
49
+ PROJECT_SUBDIRS+=("$rel:$current:${dir_langs[*]}:${dir_fws[*]}")
50
+ fi
51
+ fi
52
+ }
53
+
54
+ _check_manifest() {
55
+ local name="$1" path="$2"
56
+ # shellcheck disable=SC2178
57
+ local -n _langs="$3" _fws="$4" _manifests="$5"
58
+
59
+ case "$name" in
60
+ # JavaScript/TypeScript
61
+ package.json)
62
+ _langs+=("JavaScript")
63
+ _manifests+=("JavaScript:$path")
64
+ if grep -qE '"typescript"[[:space:]]*:' "$path" 2>/dev/null; then
65
+ _langs+=("TypeScript")
66
+ fi
67
+ if grep -qiE '"next"[[:space:]]*:' "$path" 2>/dev/null; then
68
+ _fws+=("JavaScript:Next.js")
69
+ elif grep -qiE '"nuxt"[[:space:]]*:' "$path" 2>/dev/null; then
70
+ _fws+=("JavaScript:Nuxt")
71
+ elif grep -qiE '"vite"[[:space:]]*:' "$path" 2>/dev/null; then
72
+ _fws+=("JavaScript:Vite")
73
+ elif grep -qiE '"@angular/[^\"]+"[[:space:]]*:' "$path" 2>/dev/null; then
74
+ _fws+=("JavaScript:Angular")
75
+ elif grep -qiE '"react"[[:space:]]*:' "$path" 2>/dev/null; then
76
+ _fws+=("JavaScript:React")
77
+ elif grep -qiE '"vue"[[:space:]]*:' "$path" 2>/dev/null; then
78
+ _fws+=("JavaScript:Vue")
79
+ elif grep -qiE '"svelte"[[:space:]]*:' "$path" 2>/dev/null; then
80
+ _fws+=("JavaScript:Svelte")
81
+ elif grep -qiE '"astro"[[:space:]]*:' "$path" 2>/dev/null; then
82
+ _fws+=("JavaScript:Astro")
83
+ fi
84
+ if grep -qiE '"express"[[:space:]]*:' "$path" 2>/dev/null; then
85
+ _fws+=("JavaScript:Express")
86
+ elif grep -qiE '"fastify"[[:space:]]*:' "$path" 2>/dev/null; then
87
+ _fws+=("JavaScript:Fastify")
88
+ elif grep -qiE '"@nestjs/[^\"]+"[[:space:]]*:' "$path" 2>/dev/null; then
89
+ _fws+=("JavaScript:NestJS")
90
+ elif grep -qiE '"hono"[[:space:]]*:' "$path" 2>/dev/null; then
91
+ _fws+=("JavaScript:Hono")
92
+ fi ;;
93
+ tsconfig.json) _langs+=("TypeScript"); _manifests+=("TypeScript:$path") ;;
94
+ # Python
95
+ pyproject.toml)
96
+ _langs+=("Python"); _manifests+=("Python:$path")
97
+ if grep -qi 'django' "$path" 2>/dev/null; then
98
+ _fws+=("Python:Django")
99
+ elif grep -qi 'fastapi' "$path" 2>/dev/null; then
100
+ _fws+=("Python:FastAPI")
101
+ elif grep -qi 'flask' "$path" 2>/dev/null; then
102
+ _fws+=("Python:Flask")
103
+ elif grep -qi 'pytest' "$path" 2>/dev/null; then
104
+ _fws+=("Python:pytest")
105
+ elif grep -qi 'tox' "$path" 2>/dev/null; then
106
+ _fws+=("Python:tox")
107
+ elif grep -qi 'poetry' "$path" 2>/dev/null; then
108
+ _fws+=("Python:Poetry")
109
+ fi ;;
110
+ requirements.txt|requirements-dev.txt|Pipfile|setup.py|setup.cfg)
111
+ [[ " ${_langs[*]} " == *" Python "* ]] || _langs+=("Python")
112
+ _manifests+=("Python:$path") ;;
113
+ manage.py) _langs+=("Python"); _fws+=("Python:Django"); _manifests+=("Python:$path") ;;
114
+ # Go
115
+ go.mod) _langs+=("Go"); _manifests+=("Go:$path") ;;
116
+ # Rust
117
+ Cargo.toml) _langs+=("Rust"); _manifests+=("Rust:$path") ;;
118
+ # Ruby
119
+ Gemfile) _langs+=("Ruby"); _manifests+=("Ruby:$path") ;;
120
+ # PHP
121
+ composer.json) _langs+=("PHP"); _manifests+=("PHP:$path") ;;
122
+ # Dart/Flutter
123
+ pubspec.yaml) _langs+=("Dart"); _manifests+=("Dart:$path")
124
+ grep -qi "flutter" "$path" 2>/dev/null && _fws+=("Dart:Flutter") ;;
125
+ # C/C++
126
+ CMakeLists.txt) _langs+=("C/C++"); _fws+=("C/C++:CMake"); _manifests+=("C/C++:$path") ;;
127
+ Makefile) [[ -f "$(dirname "$path")/CMakeLists.txt" ]] || _detect_c_makefile "$path" _langs _manifests ;;
128
+ # Java
129
+ pom.xml) _langs+=("Java"); _fws+=("Java:Maven"); _manifests+=("Java:$path") ;;
130
+ build.gradle|build.gradle.kts|settings.gradle*)
131
+ _langs+=("Java"); _fws+=("Java:Gradle"); _manifests+=("Java:$path")
132
+ grep -qi "kotlin" "$path" 2>/dev/null && _langs+=("Kotlin") ;;
133
+ # .NET
134
+ *.csproj|*.fsproj|*.vbproj) _langs+=("C#"); _fws+=("C#:.NET"); _manifests+=("C#:$path") ;;
135
+ # Docker
136
+ Dockerfile|docker-compose.yml|docker-compose.yaml)
137
+ _langs+=("Docker"); _manifests+=("Docker:$path") ;;
138
+ # Terraform
139
+ *.tf) _langs+=("Terraform"); _manifests+=("Terraform:$path") ;;
140
+ # Elixir
141
+ mix.exs) _langs+=("Elixir"); _manifests+=("Elixir:$path") ;;
142
+ # Haskell
143
+ *.cabal|stack.yaml) _langs+=("Haskell"); _manifests+=("Haskell:$path") ;;
144
+ # Lua
145
+ *.rockspec|.luacheckrc|selene.toml|stylua.toml) _langs+=("Lua"); _manifests+=("Lua:$path") ;;
146
+ # Swift
147
+ Package.swift) _langs+=("Swift"); _manifests+=("Swift:$path") ;;
148
+ # Julia
149
+ Project.toml|Manifest.toml) _langs+=("Julia"); _manifests+=("Julia:$path") ;;
150
+ # Zig
151
+ build.zig) _langs+=("Zig"); _manifests+=("Zig:$path") ;;
152
+ # Nix
153
+ *.nix|flake.lock) _langs+=("Nix"); _manifests+=("Nix:$path") ;;
154
+ # YAML ecosystems
155
+ *.yml|*.yaml)
156
+ if [[ "$(dirname "$path")" == *".github/workflows" ]]; then
157
+ _langs+=("GitHub Actions"); _manifests+=("GitHub Actions:$path")
158
+ elif [[ "$name" == "playbook.yml" || "$name" == "site.yml" || "$name" == "site.yaml" ]]; then
159
+ _langs+=("Ansible"); _manifests+=("Ansible:$path")
160
+ fi ;;
161
+ # Shell scripts (detect by extension + shebang)
162
+ *.sh|*.bash|*.zsh)
163
+ [[ " ${_langs[*]} " != *" Shell "* ]] && _langs+=("Shell") ;;
164
+ *.sql) [[ " ${_langs[*]} " != *" SQL "* ]] && _langs+=("SQL") ;;
165
+ *.kt|*.kts) _langs+=("Kotlin"); _manifests+=("Kotlin:$path") ;;
166
+ *.dart) _langs+=("Dart") ;;
167
+ *.rs) _langs+=("Rust") ;;
168
+ *.go) _langs+=("Go") ;;
169
+ *.rb) _langs+=("Ruby") ;;
170
+ *.php) _langs+=("PHP") ;;
171
+ *.py) _langs+=("Python") ;;
172
+ *.swift) _langs+=("Swift") ;;
173
+ *.ex|*.exs) _langs+=("Elixir") ;;
174
+ esac
175
+ }
176
+
177
+ _detect_c_makefile() {
178
+ local path="$1"
179
+ # shellcheck disable=SC2178
180
+ local -n _langs="$2" _manifests="$3"
181
+ if grep -qE '^(CC|CXX|CFLAGS|CXXFLAGS)' "$path" 2>/dev/null; then
182
+ _langs+=("C/C++"); _manifests+=("C/C++:$path")
183
+ fi
184
+ }
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env bash
2
+
3
+ declare -g _CODE_REPORT_DIR=""
4
+ declare -ga _CODE_RESULTS=()
5
+
6
+ _exec_init() {
7
+ _CODE_REPORT_DIR="$KARNEL_DATA/doctor_code_reports"
8
+ _CODE_RESULTS=()
9
+ }
10
+
11
+ _exec_run_tool() {
12
+ local tool="$1" cat="$2" cmd="$3" lang="$4" file="$5" dir="${6:-$PWD}"
13
+ local full_cmd; full_cmd="$(_tool_command "$cmd" "$file")"
14
+
15
+ if ! (cd "$dir" && _is_tool_available "$tool"); then
16
+ _CODE_RESULTS+=("__MISSING__|$lang|$tool|$cat|||")
17
+ return 2
18
+ fi
19
+
20
+ local out rc
21
+ if out="$(cd "$dir" && _run_tool_check "$tool" "$full_cmd" 30)"; then
22
+ rc=0
23
+ else
24
+ rc=$?
25
+ fi
26
+
27
+ if [[ "$out" == "__TOOL_NOT_FOUND__" ]]; then
28
+ _CODE_RESULTS+=("__MISSING__|$lang|$tool|$cat|||")
29
+ return 2
30
+ fi
31
+
32
+ local severity="info" count=0
33
+ if (( rc != 0 )); then
34
+ severity="error"
35
+ count=1
36
+ if [[ -z "$out" ]]; then
37
+ if (( rc == 124 )); then
38
+ out="Timed out after 30 seconds"
39
+ else
40
+ out="Command exited with status $rc"
41
+ fi
42
+ fi
43
+ elif [[ -z "$out" ]]; then
44
+ severity="ok"
45
+ else
46
+ local lower; lower=$(printf '%s\n' "$out" | tr '[:upper:]' '[:lower:]')
47
+ if printf '%s\n' "$lower" | grep -qE 'error|fail|critical|fatal|panic'; then
48
+ severity="error"
49
+ count=$(printf '%s\n' "$lower" | grep -cE 'error|fail|critical|fatal|panic' || true)
50
+ elif printf '%s\n' "$lower" | grep -qE 'warning|warn|deprecated|should'; then
51
+ severity="warning"
52
+ count=$(printf '%s\n' "$lower" | grep -cE 'warning|warn|deprecated|should' || true)
53
+ fi
54
+ fi
55
+
56
+ local detail line_count
57
+ detail=$(printf '%s\n' "$out" | head -5 | tr '\n' '; ')
58
+ line_count=$(printf '%s\n' "$out" | wc -l)
59
+ (( line_count > 5 )) && detail+="..."
60
+ _CODE_RESULTS+=("$severity|$lang|$tool|$cat|$count|$detail")
61
+ return "$rc"
62
+ }
63
+
64
+ _find_tool_sample() {
65
+ local tool="$1" lang="$2" dir="$3"
66
+ local -a names=()
67
+
68
+ case "$tool" in
69
+ jq) names=(-name '*.json') ;;
70
+ xmllint) names=(-name '*.xml') ;;
71
+ *)
72
+ case "$lang" in
73
+ Shell) names=(-name '*.sh' -o -name '*.bash' -o -name '*.zsh') ;;
74
+ SQL) names=(-name '*.sql') ;;
75
+ C/C++|C|C++) names=(-name '*.c' -o -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.hpp') ;;
76
+ PHP) names=(-name '*.php') ;;
77
+ Ruby) names=(-name '*.rb') ;;
78
+ Java) names=(-name '*.java') ;;
79
+ Kotlin) names=(-name '*.kt' -o -name '*.kts') ;;
80
+ Dart) names=(-name '*.dart') ;;
81
+ Lua) names=(-name '*.lua') ;;
82
+ esac
83
+ ;;
84
+ esac
85
+
86
+ [[ ${#names[@]} -gt 0 ]] || return 1
87
+ local sample
88
+ sample=$(find "$dir" \
89
+ \( -type d \( -name node_modules -o -name .git -o -name .venv -o -name venv -o -name target -o -name dist -o -name build -o -name vendor \) -prune \) -o \
90
+ \( -type f \( "${names[@]}" \) -print -quit \) 2>/dev/null)
91
+ [[ -n "$sample" ]] || return 1
92
+ printf '%s\n' "$sample"
93
+ }
94
+
95
+ _exec_run_lang() {
96
+ local lang="$1" dir="$2" mode="$3" include_global="${4:-true}"
97
+ local entry tool category cmd_run sample
98
+
99
+ while IFS= read -r entry; do
100
+ [[ -z "$entry" ]] && continue
101
+ _parse_lang_tool "$entry"
102
+ tool="${PARSED_LANG_TOOL[0]}"
103
+ category="${PARSED_LANG_TOOL[1]}"
104
+ cmd_run="${PARSED_LANG_TOOL[2]}"
105
+
106
+ sample=""
107
+ if [[ "$cmd_run" == *'{}'* ]]; then
108
+ sample=$(_find_tool_sample "$tool" "$lang" "$dir") || continue
109
+ fi
110
+ _exec_run_tool "$tool" "$category" "$cmd_run" "$lang" "$sample" "$dir" || true
111
+ done < <(_get_lang_tools "$lang" "$mode" "$include_global")
112
+ }
113
+
114
+ _exec_apply_fix() {
115
+ local tool="$1" fix_cmd="$2" lang="$3" file="$4" dir="${5:-$PWD}"
116
+ local full_cmd; full_cmd="$(_tool_command "$fix_cmd" "$file")"
117
+
118
+ if [[ "$fix_cmd" == *'{}'* && -z "$file" ]]; then
119
+ log_warn "Cannot fix — no matching file found for $tool"
120
+ return 1
121
+ fi
122
+
123
+ if ! (cd "$dir" && _is_tool_available "$tool"); then
124
+ log_warn "Cannot fix — $tool not installed"
125
+ return 1
126
+ fi
127
+
128
+ log_info "Applying fix: $tool ($lang)..."
129
+ local out rc
130
+ if out=$(cd "$dir" && timeout 60 bash -c "$full_cmd" 2>&1); then
131
+ rc=0
132
+ else
133
+ rc=$?
134
+ fi
135
+
136
+ if (( rc == 0 )); then
137
+ [[ -n "$out" ]] && log_info "$tool: $out"
138
+ log_success "$tool fix applied"
139
+ return 0
140
+ fi
141
+
142
+ log_warn "$tool fix failed (status $rc)${out:+: $out}"
143
+ return "$rc"
144
+ }
145
+
146
+ _format_report() {
147
+ local mode="${1:-text}" dir="$2"
148
+
149
+ if [[ "$mode" == "json" ]]; then
150
+ _format_json "$dir"
151
+ return
152
+ fi
153
+
154
+ local lang_count=0 tool_count=0
155
+ local -A langs_seen tools_seen
156
+
157
+ # Collect unique langs and tools
158
+ for entry in "${_CODE_RESULTS[@]}"; do
159
+ IFS='|' read -r severity lang tool cat count detail <<< "$entry"
160
+ [[ -z "$lang" || "$lang" == "__MISSING__" ]] && continue
161
+ if [[ "$lang" != "Cross-language" && -z "${langs_seen[$lang]:-}" ]]; then
162
+ langs_seen[$lang]=1
163
+ lang_count=$((lang_count + 1))
164
+ fi
165
+ [[ -z "${tools_seen[$tool]:-}" ]] && tools_seen[$tool]=1 && ((tool_count++))
166
+ done
167
+
168
+ echo
169
+ separator_section "Results"
170
+ echo
171
+
172
+ if [[ ${#_CODE_RESULTS[@]} -eq 0 ]]; then
173
+ log_info "No analysis results — no tools were executed."
174
+ echo
175
+ return
176
+ fi
177
+
178
+ local errors=0 warnings=0 infos=0 missing=0
179
+ for entry in "${_CODE_RESULTS[@]}"; do
180
+ IFS='|' read -r severity lang tool cat count detail <<< "$entry"
181
+ case "$severity" in
182
+ __MISSING__) ((missing++)) ;;
183
+ error) ((errors++)) ;;
184
+ warning) ((warnings++)) ;;
185
+ ok) ;;
186
+ *) ((infos++)) ;;
187
+ esac
188
+ done
189
+
190
+ printf " ${D_CYAN}Languages:${NC} %-2d ${D_CYAN}Tools:${NC} %-2d ${D_CYAN}Checks:${NC} %-2d\n" "$lang_count" "$tool_count" "${#_CODE_RESULTS[@]}"
191
+ echo
192
+ printf " ${D_RED}%-4s${NC} ${D_YELLOW}%-4s${NC} ${D_BLUE}%-4s${NC}\n" "Errors" "Warns" "Info"
193
+ printf " ${D_RED}%-4d${NC} ${D_YELLOW}%-4d${NC} ${D_BLUE}%-4d${NC}\n" "$errors" "$warnings" "$infos"
194
+ if (( missing > 0 )); then
195
+ echo; log_warn "$missing tool(s) not installed — install them for deeper analysis"
196
+ fi
197
+
198
+ echo
199
+ separator_section "Detailed Findings"
200
+ echo
201
+
202
+ for entry in "${_CODE_RESULTS[@]}"; do
203
+ IFS='|' read -r severity lang tool cat count detail <<< "$entry"
204
+ if [[ "$severity" == "__MISSING__" ]]; then
205
+ printf " ${D_YELLOW}⚠${NC} %s ${D_CYAN}%s${NC} %s\n" "$lang" "$tool" "(not installed)"
206
+ continue
207
+ fi
208
+ local color="$D_GREEN"
209
+ case "$severity" in
210
+ error) color="$D_RED" ;;
211
+ warning) color="$D_YELLOW" ;;
212
+ ok) color="$D_GREEN" ;;
213
+ *) color="$D_BLUE" ;;
214
+ esac
215
+ if [[ "$severity" == "ok" ]]; then
216
+ printf " ${color}✔${NC} %s ${D_CYAN}%s${NC} (%s)\n" "$lang" "$tool" "$cat"
217
+ else
218
+ printf " ${color}◈${NC} %s ${D_CYAN}%s${NC} [%s] %s\n" "$lang" "$tool" "$cat" "$(echo "$detail" | head -c 120)"
219
+ fi
220
+ done
221
+
222
+ echo
223
+ local report_file
224
+ report_file="$_CODE_REPORT_DIR/doctor_code_$(date +%Y%m%d_%H%M%S).txt"
225
+ _save_report "$report_file" "$dir"
226
+ }
227
+
228
+ _format_json() {
229
+ local dir="$1"
230
+ local first=true
231
+ echo "{"
232
+ printf ' "directory":"%s",\n' "$(_json_escape "$dir")"
233
+ echo " \"results\": ["
234
+ for entry in "${_CODE_RESULTS[@]}"; do
235
+ $first || echo ","
236
+ first=false
237
+ IFS='|' read -r severity lang tool cat count detail <<< "$entry"
238
+ printf ' {"severity":"%s","language":"%s","tool":"%s","category":"%s","count":%d,"detail":"%s"}' \
239
+ "$(_json_escape "$severity")" "$(_json_escape "$lang")" "$(_json_escape "$tool")" \
240
+ "$(_json_escape "$cat")" "${count:-0}" "$(_json_escape "$detail")"
241
+ done
242
+ echo ""
243
+ echo " ]"
244
+ echo "}"
245
+ }
246
+
247
+ _json_escape() {
248
+ local value="$1" out="" c
249
+ value="${value//\\/\\\\}"
250
+ value="${value//\"/\\\"}"
251
+ value="${value//$'\n'/\\n}"
252
+ value="${value//$'\r'/\\r}"
253
+ value="${value//$'\t'/\\t}"
254
+ value="${value//$'\b'/\\b}"
255
+ value="${value//$'\f'/\\f}"
256
+ for ((i=0; i<${#value}; i++)); do
257
+ c="${value:$i:1}"
258
+ if [[ "$c" < ' ' ]] && [[ "$c" != $'\n' ]] && [[ "$c" != $'\r' ]] && [[ "$c" != $'\t' ]]; then
259
+ printf '\\u%04x' "'$c"
260
+ else
261
+ printf '%s' "$c"
262
+ fi
263
+ done
264
+ }
265
+
266
+ _save_report() {
267
+ local file="$1" dir="$2"
268
+ {
269
+ echo "Karnel Doctor Code Report"
270
+ echo "Generated: $(date)"
271
+ echo "Directory: $dir"
272
+ echo "---"
273
+ for entry in "${_CODE_RESULTS[@]}"; do
274
+ IFS='|' read -r severity lang tool cat count detail <<< "$entry"
275
+ echo "[$severity] $lang / $tool ($cat): $detail"
276
+ done
277
+ } > "$file" 2>/dev/null && list_item "Report saved: ${D_CYAN}$file${NC}" || log_warn "Failed to save report: $file"
278
+ }