Add tagged VFS undo journal, host API, and world CLI

This commit is contained in:
2026-11-07 13:01:43 +00:00
parent a26721194e
commit 7ce839e908
26 changed files with 1568 additions and 39 deletions
+35 -3
View File
@@ -83,6 +83,7 @@ struct Entry {
command: u32,
group: u32,
cancelled: Arc<AtomicBool>,
tag: sausage_vfs::journal::Tag,
abort: AbortHandle,
}
/// One runtime keeps compiled components warm and shares the world's namespace across stores.
@@ -191,6 +192,7 @@ impl Runtime {
"http://localhost:8081",
)?),
};
router.attach_journal(world.root.journal());
let network = Arc::new(net::NetPolicy::open(&world.host_dir)?);
let engine = compiler.engine.clone();
let alive = Arc::new(AtomicBool::new(true));
@@ -313,6 +315,7 @@ impl Runtime {
self.kill_group(group);
Ok(())
}
#[allow(clippy::too_many_arguments)]
async fn start(
self: &Arc<Self>,
mut request: Request,
@@ -321,6 +324,7 @@ impl Runtime {
inherited_group: u32,
conversations: Vec<String>,
inherited_io: Option<Io>,
tool_call: Option<String>,
) -> anyhow::Result<Started> {
anyhow::ensure!(!request.argv.is_empty(), "empty argv");
let cancelled = if parent == 0 {
@@ -361,6 +365,27 @@ impl Runtime {
let pre = self.compiler.get(bytes.clone()).await?;
self.cache.lock().unwrap().insert(bytes);
let pid = self.next.fetch_add(1, Ordering::Relaxed);
let tag = if parent == 0 {
let mut tag =
sausage_vfs::journal::Tag::process(pid, executable.clone(), conversations.clone())?;
if let Some(id) = tool_call {
tag.id = id;
}
tag
} else {
self.entries
.lock()
.unwrap()
.get(&parent)
.ok_or_else(|| anyhow::anyhow!("parent exited"))?
.tag
.clone()
};
let root = self
.world
.root
.tagged(tag.clone())
.unwrap_or_else(|| self.world.root.clone());
let command = if command == 0 { pid } else { command };
let group = match request.group {
Some(0) => pid,
@@ -384,7 +409,7 @@ impl Runtime {
};
let preview1 = if matches!(pre, Compiled::Module(_)) {
Some(sausage_vfs::preview1::State::new(
self.world.root.clone(),
root.clone(),
&request.cwd,
request.argv.clone(),
request.env.clone(),
@@ -396,7 +421,7 @@ impl Runtime {
None
};
let mut mounts = Mounts::default();
mounts.mount("/", self.world.root.clone(), false);
mounts.mount("/", root, false);
let mut wasi = WasiCtxBuilder::new();
wasi.args(&request.argv)
.envs(&request.env)
@@ -499,6 +524,7 @@ impl Runtime {
command,
group,
cancelled: cancelled.clone(),
tag,
abort: task.abort_handle(),
},
);
@@ -552,6 +578,7 @@ impl Host for State {
self.group,
self.conversations.clone(),
Some(self.stdio.clone()),
None,
)
.await
{
@@ -706,6 +733,7 @@ impl Exec for Arc<Runtime> {
0,
options.conversations,
None,
options.tool_call,
);
let mut child = if let Some(deadline) = deadline {
tokio::time::timeout_at(deadline, start)
@@ -737,13 +765,17 @@ impl Exec for Arc<Runtime> {
child.code.changed().await?;
}
};
if let Some(deadline) = deadline {
let result = if let Some(deadline) = deadline {
tokio::time::timeout_at(deadline, run)
.await
.map_err(|_| anyhow::anyhow!("command timed out"))?
} else {
run.await
};
if let Some(journal) = self.world.root.journal() {
journal.retain().await?;
}
result
}
}
/// Construct the harness's shared executor over the same open world.
+1
View File
@@ -33,6 +33,7 @@ pub fn supervise(runtime: Arc<Runtime>) -> Supervisor {
0,
Vec::new(),
None,
None,
);
let child = tokio::select! { _ = &mut stop => return, child = start => child };
if let Ok(mut child) = child {