agent-migrate-core 0.6.1

Core models and transactional filesystem engine for agent configuration migration
Documentation
use std::str::FromStr;

use agent_migrate_core::{Endpoint, WatchDecision, WatchState, content_hash};

#[test]
fn same_hash_and_own_origin_are_suppressed() -> Result<(), Box<dyn std::error::Error>> {
    // Given
    let source = Endpoint::from_str("codex@local")?;
    let target = Endpoint::from_str("pi@local")?;
    let mut state = WatchState::new(source, target);
    let hash = content_hash(b"stable configuration");

    // When
    let initial = state.decide(&hash, None);
    state.record_applied(&hash);
    let unchanged = state.decide(&hash, None);
    let own_origin = state.decide("different", Some(state.origin_id()));

    // Then
    assert_eq!(initial, WatchDecision::Apply);
    assert_eq!(unchanged, WatchDecision::Unchanged);
    assert_eq!(own_origin, WatchDecision::SuppressedOrigin);
    Ok(())
}

#[test]
fn reverse_edge_shares_origin_while_unrelated_edge_does_not()
-> Result<(), Box<dyn std::error::Error>> {
    // Given
    let codex = Endpoint::from_str("codex@local")?;
    let pi = Endpoint::from_str("pi@fixture")?;
    let claude = Endpoint::from_str("claude@local")?;

    // When
    let forward = WatchState::new(codex.clone(), pi.clone());
    let reverse = WatchState::new(pi.clone(), codex);
    let onward = WatchState::new(pi, claude);

    // Then
    assert_eq!(forward.origin_id(), reverse.origin_id());
    assert_ne!(forward.origin_id(), onward.origin_id());
    assert_eq!(
        onward.decide("changed", Some(forward.origin_id())),
        WatchDecision::Apply
    );
    Ok(())
}

#[test]
fn watch_state_persists_all_loop_identity() -> Result<(), Box<dyn std::error::Error>> {
    // Given
    let temp = tempfile::tempdir()?;
    let path = temp.path().join("watch/state.json");
    let mut state = WatchState::new(
        Endpoint::from_str("claude@local")?,
        Endpoint::from_str("codex@lab")?,
    );
    state.record_applied(content_hash(b"configuration"));

    // When
    state.save(&path)?;
    let restored = WatchState::load(&path)?;

    // Then
    assert_eq!(restored, state);
    Ok(())
}