From 1b6cac325cf9f72ab7f5658dd7b0dcfa3edfa666 Mon Sep 17 00:00:00 2001 From: Surma Date: Sun, 8 Nov 2026 02:51:38 +0000 Subject: [PATCH] bundle: seed agent definitions and skills in the source snapshot --- host/tests/it/p1.rs | 95 ++++++++++++++++++++++++++++++++++++++++++--- userland/bundle.nu | 4 +- 2 files changed, 91 insertions(+), 8 deletions(-) diff --git a/host/tests/it/p1.rs b/host/tests/it/p1.rs index 120801d..f653742 100644 --- a/host/tests/it/p1.rs +++ b/host/tests/it/p1.rs @@ -1,14 +1,15 @@ -//! P1 integration: independent bundle copies and real shell calls from the durable harness. +//! P1 integration: bundle contents, source commits, extension loading, and real shell calls. use sausage::{harness::run_module, world::World}; use sausage_vfs::Open; use std::path::PathBuf; -#[tokio::test(flavor = "current_thread")] -async fn bundle_copy_and_real_shell() -> anyhow::Result<()> { +fn bundle() -> anyhow::Result { let repo = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(".."); - let bundle = PathBuf::from(std::env::var("CARGO_TARGET_DIR").unwrap()).join("bundle"); - if !bundle.join("bin/sh.wasm").exists() { - let _guard = crate::common::BUILD.lock().unwrap(); + let bundle = crate::common::target_dir().join("bundle"); + let _guard = crate::common::BUILD.lock().unwrap(); + if !bundle.join("bin/sh.wasm").exists() + || !bundle.join("src/sausage/agents/models.json").exists() + { assert!( std::process::Command::new("nu") .arg(repo.join("userland/bundle.nu")) @@ -17,9 +18,47 @@ async fn bundle_copy_and_real_shell() -> anyhow::Result<()> { .success() ); } + Ok(bundle) +} + +#[tokio::test(flavor = "current_thread")] +async fn bundle_copy_and_real_shell() -> anyhow::Result<()> { + let repo = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(".."); + let bundle = bundle()?; let dir = tempfile::tempdir()?; let world = World::open_with_userland(dir.path(), Some(&bundle))?; assert!(world.root.stat("/bin/sh.wasm", true).await?.size > 0); + let snapshot = dir.path().join("world/src/sausage"); + for path in [ + "agents/models.json", + "agents/ultimate.md", + "skills/README.md", + "extensions/README.md", + ] { + assert!(snapshot.join(path).is_file(), "missing bundled {path}"); + } + let git = |path: &std::path::Path, args: &[&str]| -> anyhow::Result { + let output = std::process::Command::new("git") + .arg("-C") + .arg(path) + .args(args) + .output()?; + anyhow::ensure!( + output.status.success(), + "git {args:?}: {}", + String::from_utf8_lossy(&output.stderr) + ); + Ok(String::from_utf8(output.stdout)?.trim().to_owned()) + }; + let message = git(&snapshot, &["log", "-1", "--format=%s"])?; + let revision = message.strip_prefix("Bundle source ").unwrap(); + for path in ["agents", "skills", "extensions"] { + assert_eq!( + git(&snapshot, &["rev-parse", &format!("HEAD:{path}")])?, + git(&repo, &["rev-parse", &format!("{revision}:{path}")])?, + "bundled {path} must match the source commit" + ); + } use std::os::unix::fs::MetadataExt; for entry in std::fs::read_dir(dir.path().join("world/bin"))? { let entry = entry?; @@ -203,3 +242,47 @@ async fn bundle_copy_and_real_shell() -> anyhow::Result<()> { assert!(world.root.stat("/bin/sh", true).await.is_err()); Ok(()) } + +#[tokio::test(flavor = "current_thread")] +async fn bundled_extensions_load() -> anyhow::Result<()> { + let bundle = bundle()?; + let dir = tempfile::tempdir()?; + let world = World::open_with_userland(dir.path(), Some(&bundle))?; + let root = world.root.clone(); + let exec = sausage::process::exec(World { + root: world.root.clone(), + host_dir: world.host_dir.clone(), + processes: world.processes.clone(), + })?; + // Use the compiled production loader without the console entrypoint or model proxy. + let (library, _) = include_str!("../../js/bundle.js") + .split_once("// main.ts") + .expect("console bundle entrypoint"); + let source = format!( + r#"{library} + const bundleModels = createModels(); + const bundleRegistry = createRegistry(); + bundleRegistry.install(CodingTools2); + bundleRegistry.install(CredentialRequests); + const bundleStorage = await openStorage(globalThis.storagePath); + const bundleHarness = await Harness.open(bundleStorage, {{ + models: bundleModels, registry: bundleRegistry, + settings: {{ get extensions() {{ return bundleRegistry.snapshot().installed(); }} }} + }}, BACKGROUND_CONTEXT); + await bundleHarness.root(BACKGROUND_CONTEXT); + const bundleLoader = await loadExtensions(bundleHarness, bundleRegistry, bundleStorage, + bundleModels, BACKGROUND_CONTEXT, [CodingTools2, CredentialRequests]); + if (bundleLoader.state().error) throw new Error(bundleLoader.state().error); + await bundleLoader.close(); + await bundleHarness.close(BACKGROUND_CONTEXT); + "# + ); + run_module(world, exec, &source).await?; + let status = root.open("/proc/extensions", Open::default()).await?; + let status: serde_json::Value = serde_json::from_slice(&status.read(0, 65536).await?)?; + let commit = + std::fs::read_to_string(dir.path().join("world/src/sausage/.git/refs/heads/main"))?; + assert_eq!(status["good"].as_str(), Some(commit.trim()), "{status}"); + assert!(status["error"].is_null(), "{status}"); + Ok(()) +} diff --git a/userland/bundle.nu b/userland/bundle.nu index 7ca2c0c..d04a56c 100644 --- a/userland/bundle.nu +++ b/userland/bundle.nu @@ -41,14 +41,14 @@ def main [destination?: path] { if ($snapshot | path exists) { rm --recursive --force $snapshot } mkdir $snapshot let archive = ($destination | path join source.tar) - ^git -C $repo archive --output $archive HEAD host vfs userland extensions Cargo.toml Cargo.lock flake.nix flake.lock README.md AGENTS.md .gitignore + ^git -C $repo archive --output $archive HEAD host vfs userland agents skills extensions Cargo.toml Cargo.lock flake.nix flake.lock README.md AGENTS.md .gitignore if $env.LAST_EXIT_CODE != 0 { error make {msg: 'source archive failed'} } ^tar -xf $archive -C $snapshot if $env.LAST_EXIT_CODE != 0 { error make {msg: 'source extraction failed'} } rm $archive ^git -C $snapshot init --quiet --initial-branch=main if $env.LAST_EXIT_CODE != 0 { error make {msg: 'source git init failed'} } - ^git -C $snapshot add host vfs userland extensions Cargo.toml Cargo.lock flake.nix flake.lock README.md AGENTS.md .gitignore + ^git -C $snapshot add host vfs userland agents skills extensions Cargo.toml Cargo.lock flake.nix flake.lock README.md AGENTS.md .gitignore if $env.LAST_EXIT_CODE != 0 { error make {msg: 'source git add failed'} } with-env { GIT_AUTHOR_NAME: 'Sausage', GIT_AUTHOR_EMAIL: 'sausage@localhost',