diff --git a/commando/core/audit.py b/commando/core/audit.py index f89202f..8c15c86 100644 --- a/commando/core/audit.py +++ b/commando/core/audit.py @@ -44,7 +44,10 @@ def search_command( all_known = state_manager.get_all_known_commands() if not headless: - session_history[base_command] = session_history.get(base_command, 0) + 1 + val = session_history.get(base_command, 0) + 1 + if base_command in session_history: + session_history.pop(base_command) + session_history[base_command] = val state_manager.save_history() if base_command in all_known: diff --git a/commando/ui/dashboard.py b/commando/ui/dashboard.py index d577615..7559d88 100644 --- a/commando/ui/dashboard.py +++ b/commando/ui/dashboard.py @@ -19,19 +19,20 @@ clear_screen, pause, save_json, + get_category_color, + format_badge, ) def print_dashboard(session_history, pending_imports): clear_screen() - print(f"{CYAN}{BOLD}=============================================={RESET}") - print(f"{CYAN}{BOLD} Terminal Command Explorer & Tutor {RESET}") - print(f"{CYAN}{BOLD}=============================================={RESET}") + print(f"{CYAN}{BOLD}╔════════════════════════════════════════════════════╗{RESET}") + print(f"{CYAN}{BOLD}║ Terminal Command Explorer & Tutor ║{RESET}") + print(f"{CYAN}{BOLD}╚════════════════════════════════════════════════════╝{RESET}\n") if session_history: - print( - f"{MAGENTA}Recent: {', '.join(list(session_history.keys())[-5:])}{RESET}\n" - ) + recent = list(session_history.keys())[-5:] + print(f"{MAGENTA}{BOLD}Recent:{RESET} {', '.join(recent)}\n") print(f" {GREEN}[1]{RESET} Explore Random Command") print(f" {GREEN}[2]{RESET} Explore by Category") @@ -44,8 +45,9 @@ def print_dashboard(session_history, pending_imports): f" {CYAN}[7]{RESET} Review Pending Imports ({len(pending_imports)} waiting)" ) print(f" {MAGENTA}[8]{RESET} Install Bash Hook") + print(f" {GREEN}[9]{RESET} View Stats & Mastery") print(f" {RED}[0]{RESET} Exit & Quiz Mode") - print(f"{YELLOW}Or type a command to search (e.g., ls, nano){RESET}\n") + print(f"\n{YELLOW}Or type a command to search (e.g., ls, nano){RESET}\n") def view_debug_log(): @@ -64,6 +66,41 @@ def view_debug_log(): pause() + +def view_stats_and_mastery(state_manager): + clear_screen() + session_history = state_manager.session_history + if not session_history: + print(f"{YELLOW}No stats available yet. Start exploring commands!{RESET}") + pause() + return + + print(f"{MAGENTA}★ User Stats & Mastery ★{RESET}\n") + print(f"Total commands explored: {len(session_history)}") + + # Sort history by mastery level (score) descending, then by name + sorted_history = sorted(session_history.items(), key=lambda x: (-x[1], x[0])) + + print(f"\n{CYAN}{BOLD}Command Mastery:{RESET}") + for cmd, score in sorted_history: + # Mastery goes up to 5 + display_score = min(5, max(0, score)) + filled = "█" * display_score + empty = "░" * (5 - display_score) + bar = f"{filled}{empty}" + + # Color coding the progress bar + if display_score >= 4: + bar_color = GREEN + if 2 <= display_score < 4: + bar_color = YELLOW + if display_score < 2: + bar_color = RED + + print(f" {bar_color}[{bar}]{RESET} {BOLD}{cmd}{RESET}") + + pause() + def factory_reset(state_manager): clear_screen() print(f"{RED}★ Factory Reset ★{RESET}\n") @@ -122,7 +159,7 @@ def explore_category(state_manager): if 0 <= idx < len(categories): selected_cat = categories[idx] clear_screen() - print(f"{YELLOW}--- {selected_cat} Commands ---{RESET}\n") + print(f"{YELLOW}--- {format_badge(selected_cat)} Commands ---{RESET}\n") for cmd, data in all_known.items(): if data["category"] == selected_cat: print(f" • {CYAN}{BOLD}{cmd}{RESET}: {data['desc']}") @@ -147,7 +184,8 @@ def manage_imports(state_manager): short_desc = ( (data["desc"][:60] + "...") if len(data["desc"]) > 60 else data["desc"] ) - print(f" • {CYAN}{BOLD}{cmd}{RESET}: {short_desc}") + badge = format_badge(data.get("category", "Custom")) + print(f" • {badge} {CYAN}{BOLD}{cmd}{RESET}: {short_desc}") print(f"\n{YELLOW}Options:{RESET}") print(f" - Type a command name to {RED}DELETE{RESET} it from the database.") @@ -222,10 +260,15 @@ def run_quiz(state_manager): if ans == q_cmd: print(f"{GREEN}Correct!{RESET}\n") - session_history[q_cmd] = min(5, session_history.get(q_cmd, 0) + 1) + val = min(5, session_history.get(q_cmd, 0) + 1) + if q_cmd in session_history: + session_history.pop(q_cmd) + session_history[q_cmd] = val score += 1 else: print(f"{RED}Incorrect.{RESET} The answer was '{BOLD}{q_cmd}{RESET}'.\n") + if q_cmd in session_history: + session_history.pop(q_cmd) session_history[q_cmd] = 0 save_json(HISTORY_FILE, session_history) @@ -261,7 +304,7 @@ def review_pending_imports(state_manager): clear_screen() data = pending_imports[cmd] print(f"{CYAN}Command:{RESET} {cmd}") - print(f"Category: [{MAGENTA}{data['category']}{RESET}]") + print(f"Category: {format_badge(data['category'])}") print(f"Explanation: {data['desc']}") print(f"Example: {data['example']}") print( @@ -407,6 +450,9 @@ def main_loop(state_manager, search_command_fn, auto_scan_fn): elif raw_input == "8": install_bash_hook() continue + elif raw_input == "9": + view_stats_and_mastery(state_manager) + continue elif raw_input == "0" or raw_input.lower() == "done": choice = ( input( diff --git a/commando/utils/io.py b/commando/utils/io.py index 92a4fd5..e58a6bb 100644 --- a/commando/utils/io.py +++ b/commando/utils/io.py @@ -81,3 +81,22 @@ def pause(): input(f"\n{YELLOW}Press Enter to continue...{RESET}") except (EOFError, KeyboardInterrupt): print() + + +def get_category_color(category): + cat_lower = category.lower() + if "file" in cat_lower or "disk" in cat_lower: + return CYAN + if "network" in cat_lower or "web" in cat_lower: + return MAGENTA + if "process" in cat_lower or "system" in cat_lower: + return RED + if "navig" in cat_lower or "search" in cat_lower: + return GREEN + if "text" in cat_lower or "edit" in cat_lower: + return YELLOW + return BOLD + +def format_badge(category): + color = get_category_color(category) + return f"[{color}{category}{RESET}]"