bade5b81f7
TUI rewrite (the visible half of the change): - 8 views instead of 6: Home, Search, Info, Install, Build, Query, Remove, Updates — central VIEW_ORDER const in tui/views/mod.rs and cycle_view() / parent_view() helpers mean adding a 9th view is one line. - Help overlay is now view-scoped: shows a Global section and an In this view section that only lists keybindings the current view actually honors. - Esc goes back one view (parent_view map); q still quits. - New ConfirmAction enum and full-screen confirm_banner widget: pressing i / b / r / U now sets pending_confirm and shows a banner; y confirms, n cancels. - TUI build routed through the canonical fetch_aur_to_store + validate_git_target instead of an inline git clone. The 6 swallowed errors are now surfaced in build_log and status_message. - panic-catching wrapper around spawn_action so a panic in the worker thread becomes a visible ActionUpdate instead of a frozen spinner. - TUI cancel architecture: Arc<Mutex<Option<Child>>> shared between parent and worker drainer, Arc<AtomicBool> cancel flag, c keypress in Install/Build views calls child.kill(). - Terminal too-small guard: < 14 rows or < 40 cols renders a Terminal too small overlay instead of broken layout. - Sticky error coloring in the status bar: success uses theme.success, failure uses theme.error, neutral uses status_style. - PgUp / PgDn global scroll bindings for Install/Build log views; scroll position tracked in install_log_scroll / build_log_scroll u16 fields; install_log_joined / build_log_joined pre-joined strings avoid repeated Vec<String>::join calls during render. - CubApp::new() returns Result<Self, CubError>; HOME missing or store.init() failure is now a fatal error overlay instead of a silent /tmp/.cub fallback. AUR hardening: - AUR client (reqwest::blocking::Client) gets 5s connect + 15s request timeouts. - fetch_aur_to_store writes the recipe atomically: stage in store.tmp_dir()/recipe-staging-<name>-<nanos>, then fs::rename. TmpGuard drop cleans up the clone directory. - validate_git_target rejects names with .., ://, leading -, empty, or NUL bytes (was previously only catching leading -). - redox-pkg dependency pinned to rev 52f7930f8e6dfbe85efd115b3848ea802e1a56f0 to match the resolved Cargo.lock. God-module split (main.rs 2063 -> 1723 lines): - constants.rs: 10 path / URL constants. - bur_helpers.rs: search_cached_bur, ensure_bur_package_dir, sync_bur_repo, default_bur_repo_url, bur_repo_dir, aur_repo_url, BurMatch struct. - fs_helpers.rs: find_stage_dir, directory_has_entries, copy_dir_recursive, remove_dir_if_exists, current_unix_timestamp, join_strings, join_package_names, empty_if_blank, yes_no. - paths.rs: cub_temp_dir, validate_git_target. Tests: - 19 unit tests in main-side modules (was 5); 121 in the lib (unchanged). Total 140/140 pass. - New CubError variant tests, validate_git_target happy-path + 4 attack vectors, cub_temp_dir unique-name under concurrent calls, bur_repo_dir / aur_repo_url composition, fs_helpers round-trips with tempfile scratch dirs. Policy: - local/AGENTS.md gains a TUI CONVENTION section: single binary, -i flag, no separate -tui crate, ratatui 0.30 + termion 4.0.6, anti-pattern list. cub, redbear-info, and redbear-netctl-console are listed as already compliant. - cubl (the cub lib-only consumer) recipe path updated from -p cub-cli to -p cub. Verified: cargo build --workspace and --no-default-features and --features full and --features tui all clean; cargo test --workspace 140/140 pass; cub --version cub 0.2.3; cub --help 21 subcommands.