pitboard-core 0.4.0

The engine behind pitboard: parking and restoring Claude Code and Codex logins. Serves pitboard's own front ends.
Documentation
//! Dropping an account and the credentials parked for it.

use super::{Error, Result, Settled, purge};
use crate::provider;
use crate::service::Warning;
use crate::state::{self, Key};

/// Returns the account's email.
pub fn forget(settled: Settled, key: &Key) -> Result<(String, Vec<Warning>)> {
    let Settled {
        _exclusive,
        mut state,
        ctx,
    } = settled;
    // Who is signed in is a fact about the machine. pitboard's record of its last switch
    // is stale the moment someone signs in with the tool's own login command, and
    // forgetting the account that is actually in use throws away the only record of it.
    // Asked of the tool's own files, so it answers offline: Claude Code's config, or a
    // Codex login's own claims.
    let live_uuid = provider::of(key.provider)
        .recorded_identity(&ctx)
        .map(|found| found.account_id);
    let signed_in = match (&live_uuid, state.get(key)) {
        (Some(uuid), Some(account)) => &account.account_uuid == uuid,
        // No live identity to compare against, so pitboard's own record of the last switch
        // is all there is.
        _ => state.active_for(key.provider) == Some(key.label.as_str()),
    };
    if signed_in {
        return Err(Error::CannotForgetActiveAccount { label: key.typed() });
    }
    let enrolled = state.labels(key.provider);
    let account = state.remove(key).ok_or_else(|| Error::AccountUnknown {
        label: key.typed(),
        enrolled,
    })?;
    state::save(&ctx, &state)?;
    crate::fault::point("forget.recorded");
    crate::readings::forget(&ctx, &account.account_uuid);
    crate::budget::forget(&ctx, &account.account_uuid);
    crate::history::forget(&ctx, &account.account_uuid);
    let pending = purge(&ctx, &mut state);
    Ok((
        account.email,
        (pending > 0)
            .then_some(Warning::ParksPendingRemoval(pending))
            .into_iter()
            .collect(),
    ))
}