Single-commit clean baseline after security scrub of niche-tells, project codenames, internal jargon, and contributor-email leaks. Contents: - 100 Rust crates (_primitives/_rust/) - 37 agent manifests (_manifests/) + generated specs (_generated/) - 67 user-invocable skills (skills/) - 33 hooks (hooks/) - Composition blocks (_blocks/) - Documentation (docs/, README.md) - TS adapter packages (_ts_packages/) - Assembler (_assembler/) - Roles (_roles/) - Templates (_templates/) - Forgejo CI (.forgejo/) Author: Denis Parfionovich <info@greendragon.info> License: see LICENSE.
153 lines
5.1 KiB
Rust
153 lines
5.1 KiB
Rust
//! Shared helpers for rule_blocks integration tests.
|
|
//! Separate from `common/mod.rs` because these helpers depend on rusqlite
|
|
//! and are only needed by rule_blocks tests.
|
|
|
|
use rusqlite::Connection;
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
use tempfile::TempDir;
|
|
|
|
pub fn seed_schema(conn: &Connection) {
|
|
conn.execute_batch(
|
|
"CREATE TABLE IF NOT EXISTS blocks (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
dna TEXT NOT NULL UNIQUE,
|
|
block_type TEXT NOT NULL,
|
|
name TEXT NOT NULL,
|
|
path TEXT NOT NULL,
|
|
caps TEXT NOT NULL,
|
|
scope_sha TEXT NOT NULL,
|
|
body_sha TEXT NOT NULL,
|
|
nonce TEXT NOT NULL,
|
|
created INTEGER NOT NULL,
|
|
modified INTEGER NOT NULL,
|
|
superseded_by TEXT
|
|
);",
|
|
)
|
|
.expect("create schema");
|
|
}
|
|
|
|
pub fn insert_rule(conn: &Connection, name: &str, path: &str) {
|
|
conn.execute(
|
|
"INSERT INTO blocks \
|
|
(dna, block_type, name, path, caps, scope_sha, body_sha, nonce, created, modified)
|
|
VALUES (?1, 'rule', ?2, ?3, 'md', 'aa', 'bb', 'cc', 0, 0)",
|
|
rusqlite::params![
|
|
format!("rule::md::aaaa::bbbb-cccc-{name}"),
|
|
name,
|
|
path,
|
|
],
|
|
)
|
|
.expect("insert rule");
|
|
}
|
|
|
|
/// Create a temp directory with the assembler fixture structure + write a
|
|
/// manifest TOML with the given `rule_blocks` field.
|
|
/// Returns (TempDir guard, kit root path, registry DB path).
|
|
pub fn setup_kit(
|
|
rule_blocks: &[&str],
|
|
frag_files: &[(&str, &str)],
|
|
) -> (TempDir, PathBuf, PathBuf) {
|
|
let tmp = TempDir::new().expect("mktempdir");
|
|
let root = tmp.path().to_path_buf();
|
|
|
|
let fx = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
.join("tests")
|
|
.join("fixtures");
|
|
let kit = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
.parent()
|
|
.unwrap()
|
|
.to_path_buf();
|
|
|
|
copy_dir(&fx.join("_manifests"), &root.join("_manifests"));
|
|
copy_dir(&fx.join("_blocks"), &root.join("_blocks"));
|
|
copy_dir(&kit.join("_roles"), &root.join("_roles"));
|
|
copy_caps(&kit.join("_capabilities"), &root.join("_capabilities"));
|
|
|
|
let db_path = root.join("registry.sqlite");
|
|
let conn = Connection::open(&db_path).expect("open db");
|
|
seed_schema(&conn);
|
|
|
|
let frags_dir = root.join("_rule_frags");
|
|
fs::create_dir_all(&frags_dir).expect("mkdir frags");
|
|
for (name, body) in frag_files {
|
|
let file = frags_dir.join(format!("{}.md", name.replace("::", "--")));
|
|
fs::write(&file, body).expect("write frag");
|
|
insert_rule(&conn, name, file.to_str().unwrap());
|
|
}
|
|
drop(conn);
|
|
|
|
let rule_blocks_toml = if rule_blocks.is_empty() {
|
|
String::new()
|
|
} else {
|
|
let list = rule_blocks
|
|
.iter()
|
|
.map(|s| format!("\"{}\"", s))
|
|
.collect::<Vec<_>>()
|
|
.join(", ");
|
|
format!("rule_blocks = [{}]\n", list)
|
|
};
|
|
|
|
let manifest = format!(
|
|
"name = \"test-rule-blocks\"\n\
|
|
description = \"test manifest for rule_blocks integration tests\"\n\
|
|
tools = [\"Read\"]\n\
|
|
model = \"opus\"\n\
|
|
substrate_role = \"read-only\"\n\
|
|
role = \"Test role text.\"\n\
|
|
blocks = [\"baseline\", \"evidence-grading\", \"memory-protocol\"]\n\
|
|
domain_in = [\"test domain\"]\n\
|
|
forbidden_domain = [\"forbidden action\"]\n\
|
|
{rule_blocks_toml}\n\
|
|
[[handoff]]\n\
|
|
target = \"architect\"\n\
|
|
trigger = \"test handoff\"\n"
|
|
);
|
|
fs::write(
|
|
root.join("_manifests").join("test-rule-blocks.toml"),
|
|
manifest,
|
|
)
|
|
.expect("write manifest");
|
|
|
|
(tmp, root, db_path)
|
|
}
|
|
|
|
pub fn copy_dir(from: &Path, to: &Path) {
|
|
fs::create_dir_all(to).expect("mkdir dst");
|
|
if !from.is_dir() {
|
|
return;
|
|
}
|
|
for entry in fs::read_dir(from).expect("read src").flatten() {
|
|
let p = entry.path();
|
|
if p.is_file() {
|
|
fs::copy(&p, to.join(p.file_name().unwrap())).expect("copy file");
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn copy_caps(from: &Path, to: &Path) {
|
|
fs::create_dir_all(to).expect("mkdir caps root");
|
|
for cat in fs::read_dir(from).expect("read caps").flatten() {
|
|
let cat_path = cat.path();
|
|
if !cat_path.is_dir() {
|
|
continue;
|
|
}
|
|
let cat_dst = to.join(cat_path.file_name().unwrap());
|
|
fs::create_dir_all(&cat_dst).expect("mkdir cat");
|
|
for slug in fs::read_dir(&cat_path).expect("read cat").flatten() {
|
|
let slug_path = slug.path();
|
|
if !slug_path.is_dir() {
|
|
continue;
|
|
}
|
|
let slug_dst = cat_dst.join(slug_path.file_name().unwrap());
|
|
fs::create_dir_all(&slug_dst).expect("mkdir slug");
|
|
for file in fs::read_dir(&slug_path).expect("read slug").flatten() {
|
|
let fp = file.path();
|
|
if fp.is_file() {
|
|
fs::copy(&fp, slug_dst.join(fp.file_name().unwrap()))
|
|
.expect("copy cap file");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|