remem-ai 0.6.93

Local-first coding agent memory for Claude Code and OpenAI Codex
Documentation
use anyhow::{Context, Result};
use std::path::Path;
use std::process::Command;

use crate::db::{self, test_support::ScopedTestDataDir};

fn run_summary_git(repo: &Path, args: &[&str]) -> Result<String> {
    let output = Command::new("git").args(args).current_dir(repo).output()?;
    anyhow::ensure!(
        output.status.success(),
        "git {} failed: {}",
        args.join(" "),
        String::from_utf8_lossy(&output.stderr)
    );
    Ok(String::from_utf8_lossy(&output.stdout).trim().to_string())
}

fn init_summary_repo(path: &Path) -> Result<()> {
    std::fs::create_dir_all(path)?;
    run_summary_git(path, &["init"])?;
    run_summary_git(
        path,
        &["config", "user.email", "remem-test@example.invalid"],
    )?;
    run_summary_git(path, &["config", "user.name", "Remem Test"])?;
    Ok(())
}

fn commit_summary_file(path: &Path, contents: &str, message: &str) -> Result<String> {
    std::fs::write(path.join("summary-evidence.txt"), contents)?;
    run_summary_git(path, &["add", "summary-evidence.txt"])?;
    run_summary_git(path, &["commit", "-m", message])?;
    run_summary_git(path, &["rev-parse", "HEAD"])
}

#[test]
fn replayed_stop_spill_uses_spilled_commit_evidence_when_head_moves() -> Result<()> {
    let test_dir = ScopedTestDataDir::new("stop-spill-git-snapshot");
    let repo = test_dir.path.join("repo");
    init_summary_repo(&repo)?;
    let sha_a = commit_summary_file(&repo, "commit-a", "commit a")?;
    let repo_str = repo.to_string_lossy();
    let metadata_a = crate::git_util::detect_commit_metadata(&repo_str)?
        .context("commit A metadata should be detectable")?;
    let evidence_a = crate::git_util::GitCommitEvidence {
        kind: crate::git_util::GitEvidenceKind::ObservedCommit,
        metadata: metadata_a,
        locator: Some("codex_call:test".to_string()),
    };
    let input = serde_json::json!({
        "session_id": "session-stop-spill-git",
        "cwd": repo,
        "last_assistant_message": "Finished the work"
    })
    .to_string();
    super::spill::spill_summary_hook_payload_with_git_evidence(
        &input,
        Some("codex-cli"),
        None,
        Some(&repo_str),
        &[evidence_a],
        &anyhow::anyhow!("database unavailable"),
    )?;
    let sha_b = commit_summary_file(&repo, "commit-b", "commit b")?;
    assert_ne!(sha_a, sha_b);

    let mut conn = db::open_db()?;
    let replayed = super::spill::replay_spilled_summary_hook_payloads(&conn, |conn, record| {
        super::hook::enqueue_summary_payload_with_git_evidence(
            conn,
            &record.input,
            record.host.as_deref(),
            record.profile.as_deref(),
            super::replay::SummaryPayloadOrigin::Replay,
            Some(&record.git_evidence),
        )
    })?;
    assert_eq!(replayed, 1);
    let stored_sha: String = conn.query_row(
        "SELECT evidence.sha
         FROM captured_event_commits evidence
         JOIN captured_events events ON events.id = evidence.event_row_id
         WHERE events.session_id = 'session-stop-spill-git'",
        [],
        |row| row.get(0),
    )?;
    assert_eq!(stored_sha, sha_a);

    let task = db::claim_next_extraction_task(&mut conn, "worker-stop-link", 60)?
        .context("replayed Stop should enqueue SessionRollup")?;
    assert_eq!(task.task_kind, db::ExtractionTaskKind::SessionRollup);
    let linked = crate::captured_git::link_task_range(&mut conn, &task)?;
    assert_eq!(linked.len(), 1);
    assert_eq!(linked[0].sha, sha_a);
    let linked_sha: String = conn.query_row(
        "SELECT commits.sha
         FROM git_commit_sessions links
         JOIN git_commits commits ON commits.id = links.commit_id",
        [],
        |row| row.get(0),
    )?;
    assert_eq!(linked_sha, sha_a);
    Ok(())
}