use crate::boundary::dispatch::Deps;
use crate::boundary::tests::snapshot;
use crate::cli_outbound::Cli;
use crate::control::policy::CAPABILITY_YAML;
use std::path::PathBuf;
use std::sync::Arc;
use tempfile::{TempDir, tempdir};
pub(super) const AGENT: &str = "20260101T000000Z-a1";
pub(super) struct World {
pub(super) dir: TempDir,
}
impl World {
pub(super) fn new() -> World {
World {
dir: tempdir().expect("tempdir"),
}
}
pub(super) fn workspace(&self) -> PathBuf {
self.dir.path().join("names").join("alba")
}
pub(super) fn state(&self) -> PathBuf {
self.dir.path().join("state")
}
pub(super) fn deps(&self) -> Deps {
Deps {
litany: Cli::new("/usr/bin/true"),
bl: Cli::new("/no/such/bl"),
state_root: self.state(),
home: self.dir.path().join("home"),
yog_data_root: self.dir.path().join("data"),
yog_binary: PathBuf::from("/no/such/yog"),
world: crate::xdg::Env::from_env(),
snapshot: Arc::new(snapshot(&self.workspace(), "alba", Vec::new(), Vec::new())),
caller: crate::boundary::dispatch::Caller::default(),
}
}
fn git(&self, args: &[&str]) -> std::process::Output {
crate::git_env::output(
crate::git_env::git()
.args(["-c", "user.email=t@t.local", "-c", "user.name=T"])
.arg("--git-dir")
.arg(self.workspace().join("repo.git"))
.args(args),
)
.expect("git runs")
}
pub(super) fn repo(&self) {
std::fs::create_dir_all(self.workspace().join("repo.git")).unwrap();
self.git(&["init", "--bare", "-q"]);
}
pub(super) fn park(&self, agent: &str, tool_use: &str) {
self.park_as(
agent,
tool_use,
"bash",
"bash {\"command\":\"curl x\"} classified open-world (`curl` reaches the network)",
);
}
pub(super) fn park_as(&self, agent: &str, tool_use: &str, tool: &str, reason: &str) {
let staged = self.dir.path().join("mark.json");
let blob = serde_json::json!({
"tool_use_id": tool_use, "tool": tool, "reason": reason,
});
std::fs::write(&staged, blob.to_string()).unwrap();
let hashed = self.git(&["hash-object", "-w", "--", &staged.to_string_lossy()]);
let oid = String::from_utf8_lossy(&hashed.stdout).trim().to_owned();
self.git(&[
"update-ref",
&format!("refs/litany/held/{agent}"),
oid.as_str(),
]);
}
pub(super) fn policy(&self, text: &str) {
let staged = self.dir.path().join(CAPABILITY_YAML);
std::fs::write(&staged, text).unwrap();
let hashed = self.git(&["hash-object", "-w", "--", &staged.to_string_lossy()]);
let blob = String::from_utf8_lossy(&hashed.stdout).trim().to_owned();
self.git(&[
"update-index",
"--add",
"--cacheinfo",
"100644",
&blob,
CAPABILITY_YAML,
]);
let tree = self.git(&["write-tree"]);
let tree = String::from_utf8_lossy(&tree.stdout).trim().to_owned();
let written = self.git(&["commit-tree", &tree, "-m", "policy"]);
let commit = String::from_utf8_lossy(&written.stdout).trim().to_owned();
let why = String::from_utf8_lossy(&written.stderr).into_owned();
assert!(!commit.is_empty(), "commit-tree wrote nothing: {why}");
self.git(&["update-ref", "refs/heads/config/default", &commit]);
}
}