mod rig;
pub(crate) use rig::Rig;
use super::*;
use crate::cli_outbound::Cli;
use crate::git_tree::tests::fixture::Fixture;
use crate::git_tree::{Agent, AgentState};
use crate::projects::runner::BlStore;
use crate::test_support::FakeClock;
use crate::xdg::Env;
use std::path::PathBuf;
use tempfile::{TempDir, tempdir};
pub(crate) fn no_balls() -> BlStore {
let xdg = Env::from_pairs([("HOME", "/nonexistent")]).balls_layout();
BlStore::new(xdg, Cli::new("bl"))
}
pub(crate) struct Harness {
_root: TempDir,
pub(crate) fx: Fixture,
pub(crate) roots: Roots,
pub(crate) ws: PathBuf,
added: Vec<Fixture>,
}
impl Harness {
pub(crate) fn new() -> Self {
let mut h = Self::pristine();
std::fs::create_dir_all(h.roots.workspaces()).unwrap();
h.fx.build_agent("c-1", "hello");
h.ws = h.roots.workspaces().join("ws");
std::os::unix::fs::symlink(&h.fx.path, &h.ws).unwrap();
h
}
pub(crate) fn pristine() -> Self {
let root = tempdir().unwrap();
let roots = Roots {
yog_data: root.path().join("yog"),
litany_data: root.path().join("litany"),
yog_state: root.path().join("state"),
balls_clones: root.path().join("balls").join("clones"),
home: root.path().join("home"),
world: crate::test_support::world_under(root.path()),
};
std::fs::create_dir_all(&roots.yog_state).unwrap();
let ws = roots.workspaces().join("ws");
Self {
_root: root,
fx: Fixture::new(),
roots,
ws,
added: Vec::new(),
}
}
pub(crate) fn mint_named(&mut self, name: &str, agent: &str) -> PathBuf {
std::fs::create_dir_all(self.roots.names()).unwrap();
self.add_at(self.roots.names().join(name), agent)
}
pub(crate) fn add_workspace(&mut self, name: &str, agent: &str) -> PathBuf {
self.add_at(self.roots.workspaces().join(name), agent)
}
pub(crate) fn add_replay(&mut self, name: &str, agent: &str) -> PathBuf {
std::fs::create_dir_all(self.roots.replays()).unwrap();
self.add_at(self.roots.replays().join(name), agent)
}
fn add_at(&mut self, ws: PathBuf, agent: &str) -> PathBuf {
let fx = Fixture::new();
fx.build_agent(agent, "hi");
std::os::unix::fs::symlink(&fx.path, &ws).unwrap();
self.added.push(fx);
ws
}
pub(crate) fn last_added(&self) -> &Fixture {
self.added.last().expect("a workspace was added")
}
pub(crate) fn build_more(&self, id: &str, msg: &str) {
self.fx.build_agent(id, msg);
}
pub(crate) fn model(&self) -> (FakeClock, Rig) {
let clock = FakeClock::new();
let (model, deriver) = AppModel::boot(
self.roots.clone(),
clock.arc(),
Box::new(no_balls()),
Some("me".to_string()),
);
(clock, Rig { model, deriver })
}
}
pub(crate) fn agent(id: &str, state: AgentState) -> Agent {
Agent {
branch_name: format!("agents/{id}"),
agent_id: id.to_string(),
tip_oid: "d".repeat(40),
tip_short_oid: "dddddddd".into(),
tip_timestamp_unix: 4,
last_action_unix: 4,
messages: 0,
steps: vec![],
preview: None,
stream: crate::git_tree::Stream::default(),
tool_calls: Vec::new(),
state,
state_uncertain: false,
truncated: false,
failure: None,
flagged: None,
pending: vec![],
conflicted_oid: None,
budget_oid: None,
abandoned_oid: None,
notify_oid: None,
held: None,
goal_ball: None,
name: None,
goal_name: None,
call_start_unix: None,
}
}