bundle: seed agent definitions and skills in the source snapshot
This commit is contained in:
+89
-6
@@ -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<PathBuf> {
|
||||
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<String> {
|
||||
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(())
|
||||
}
|
||||
|
||||
+2
-2
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user