tokf 0.2.33

Config-driven CLI tool that compresses command output before it reaches an LLM context
Documentation
use tokf::auth::client::is_secure_url;
use tokf::auth::credentials::LoadedAuth;
use tokf::remote::http::{Client, load_auth};
use tokf::remote::{client, machine};
use uuid::Uuid;

/// Result of machine registration.
pub enum RegisterResult {
    /// Machine was already registered; re-synced with server.
    AlreadyRegistered {
        machine_id: String,
        hostname: String,
    },
    /// Machine was newly registered.
    NewlyRegistered {
        machine_id: String,
        hostname: String,
    },
}

/// Register this machine with the tokf server using the provided auth.
///
/// Generates a UUID v4 machine identifier, registers it with the server, and
/// stores it in `~/.config/tokf/machine.toml`. If already registered locally,
/// re-syncs with the server to repair any stale state (idempotent).
///
/// # Errors
///
/// Returns an error if the server is unreachable or registration fails.
pub fn register_machine(auth: &LoadedAuth) -> anyhow::Result<RegisterResult> {
    let http_client = Client::new(&auth.server_url, Some(&auth.token))?;

    if let Some(m) = machine::load() {
        client::register_machine(&http_client, &m.machine_id, &m.hostname)?;
        Ok(RegisterResult::AlreadyRegistered {
            machine_id: m.machine_id,
            hostname: m.hostname,
        })
    } else {
        let machine_id = Uuid::new_v4().to_string();
        let hostname = gethostname::gethostname().to_string_lossy().into_owned();
        client::register_machine(&http_client, &machine_id, &hostname)?;
        machine::save(&machine_id, &hostname)?;
        Ok(RegisterResult::NewlyRegistered {
            machine_id,
            hostname,
        })
    }
}

/// Register this machine with the tokf server.
///
/// Generates a UUID v4 machine identifier, registers it with the server, and
/// stores it in `~/.config/tokf/machine.toml`. If already registered locally,
/// re-syncs with the server to repair any stale state (idempotent).
///
/// # Errors
///
/// Returns an error if the user is not logged in, the token is expired, or
/// the server is unreachable.
pub fn cmd_remote_setup() -> anyhow::Result<i32> {
    let auth = load_auth()?;

    if !is_secure_url(&auth.server_url) {
        eprintln!(
            "[tokf] warning: server URL uses plain HTTP — your token may be exposed in transit"
        );
    }

    match register_machine(&auth)? {
        RegisterResult::AlreadyRegistered {
            machine_id,
            hostname,
        } => {
            eprintln!("[tokf] Already registered: {machine_id} ({hostname})");
        }
        RegisterResult::NewlyRegistered {
            machine_id,
            hostname,
        } => {
            eprintln!("[tokf] Machine registered: {machine_id} ({hostname})");
        }
    }

    Ok(0)
}

/// Show remote sync registration state.
#[allow(clippy::unnecessary_wraps)] // Returns Result for or_exit() consistency
pub fn cmd_remote_status() -> anyhow::Result<i32> {
    match machine::load() {
        Some(m) => {
            println!("Machine ID: {}", m.machine_id);
            println!("Hostname:   {}", m.hostname);
        }
        None => {
            println!("Not registered. Run `tokf remote setup` to register this machine.");
        }
    }
    Ok(0)
}

/// Sync local usage events to the remote server.
///
/// # Errors
///
/// Returns an error if the user is not logged in, no machine is registered,
/// or the server is unreachable.
pub fn cmd_remote_sync() -> anyhow::Result<i32> {
    use tokf::tracking;

    let auth = load_auth()?;

    let machine = machine::load()
        .ok_or_else(|| anyhow::anyhow!("machine not registered. Run `tokf remote setup` first"))?;

    let db_path =
        tracking::db_path().ok_or_else(|| anyhow::anyhow!("cannot determine tracking DB path"))?;
    let conn = tracking::open_db(&db_path)?;

    let pending = tracking::get_pending_count(&conn)?;
    if pending == 0 {
        eprintln!("[tokf] Nothing to sync");
        return Ok(0);
    }

    let result = tokf::sync_core::perform_sync(&auth, &machine, &conn)?;
    eprintln!(
        "[tokf] Synced {} event(s). Cursor: {}.",
        result.synced_count, result.cursor
    );

    Ok(0)
}

/// Backfill `filter_hash` for past events that have a filter name but no hash.
///
/// Discovers all currently-installed filters, then updates every event row in the
/// local DB where `filter_hash IS NULL` but `filter_name` is known. Events for
/// filters that have been removed or renamed are reported but left unchanged.
///
/// # Errors
/// Returns an error if filter discovery or DB access fails.
pub fn cmd_remote_backfill(no_cache: bool) -> anyhow::Result<i32> {
    use tokf::tracking;

    let filters = crate::resolve::discover_filters(no_cache)?;

    let db_path =
        tracking::db_path().ok_or_else(|| anyhow::anyhow!("cannot determine tracking DB path"))?;
    let conn = tracking::open_db(&db_path)?;

    let (updated, not_found) = tracking::backfill_filter_hashes(&conn, &filters)?;

    if updated == 0 && not_found.is_empty() {
        eprintln!("[tokf] Nothing to backfill — all events already have hashes.");
        return Ok(0);
    }

    if updated > 0 {
        eprintln!("[tokf] Backfilled hash for {updated} event(s).");
    }
    if !not_found.is_empty() {
        eprintln!(
            "[tokf] {} filter(s) not found (removed or renamed): {}",
            not_found.len(),
            not_found.join(", ")
        );
    }

    Ok(0)
}