CI: remove k8s stages, fix the Docker-level pipeline green
Survey + fixes so the pipeline passes at the Docker level (no k8s).
- Remove k8s: drop the `sandbox-k8s` job (kind/Calico/--features k8s-tests) and the
"Helm chart lints" gate step. release.yml was already k8s-clean.
- Rust job:
- `cargo fmt --all` — fix pre-existing formatting drift (fmt --check was failing).
- clippy -D warnings: fix 3 lib warnings (cm-brain sort_by_key→Reverse, cm-api
fleet.rs doc list indentation, node_rules map_or→is_none_or).
- Regenerate the .sqlx offline cache (was missing the cm-runtime run_loop test
query → offline compile failed). DB-backed tests use testcontainers at runtime.
- Set SQLX_OFFLINE=true on the rust + e2e jobs so query! macros compile against
the committed cache deterministically (no DB needed at compile time).
- Frontend job:
- Fix the 1 ESLint error (useAgentTelemetry: no setState-synchronously-in-effect;
tag the slice with agentId + derive null on mismatch).
- Fix 2 stale panel-params tests (`terminal` is a valid app id now; assert the
current APP_IDS + use a genuinely-unknown id for the reject case).
Verified locally: fmt clean, clippy --all-targets -D warnings clean (offline),
frontend lint 0 errors, tsc clean, 86/86 frontend tests pass, build OK.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a36b2c87ac
commit
3554a3aaf2
+126
-29
@@ -77,7 +77,11 @@ pub async fn pull(reference: &str, dest: &Path) -> Result<PulledBrain, BrainErro
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
r
|
||||
};
|
||||
Ok(PulledBrain { meta, name, system_prompt })
|
||||
Ok(PulledBrain {
|
||||
meta,
|
||||
name,
|
||||
system_prompt,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize)]
|
||||
@@ -102,7 +106,15 @@ pub async fn list(query: &str) -> Result<Vec<BrainListing>, BrainError> {
|
||||
search_one(&client, q).await?
|
||||
} else {
|
||||
const SEEDS: &[&str] = &[
|
||||
"assistant", "agent", "code", "react", "data", "research", "write", "general", "support",
|
||||
"assistant",
|
||||
"agent",
|
||||
"code",
|
||||
"react",
|
||||
"data",
|
||||
"research",
|
||||
"write",
|
||||
"general",
|
||||
"support",
|
||||
];
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
let mut out = Vec::new();
|
||||
@@ -137,7 +149,10 @@ async fn filter_loadable(raw: Vec<BrainListing>) -> Vec<BrainListing> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn search_one(client: &BrainRegistryClient, q: &str) -> Result<Vec<BrainListing>, BrainError> {
|
||||
async fn search_one(
|
||||
client: &BrainRegistryClient,
|
||||
q: &str,
|
||||
) -> Result<Vec<BrainListing>, BrainError> {
|
||||
let entries = client.list(Some(q), None, None).await.map_err(be)?;
|
||||
let mut out = Vec::new();
|
||||
for e in entries {
|
||||
@@ -191,8 +206,15 @@ fn section_text(s: Option<String>) -> SectionText {
|
||||
|
||||
/// Pull a brain and summarize its sections without applying it to any agent.
|
||||
pub async fn preview(reference: &str) -> Result<BrainPreview, BrainError> {
|
||||
let safe: String = reference.chars().map(|c| if c == '/' || c == ':' { '_' } else { c }).collect();
|
||||
let tmp = std::env::temp_dir().join(format!("cm-brain-preview-{}-{}.brain", std::process::id(), safe));
|
||||
let safe: String = reference
|
||||
.chars()
|
||||
.map(|c| if c == '/' || c == ':' { '_' } else { c })
|
||||
.collect();
|
||||
let tmp = std::env::temp_dir().join(format!(
|
||||
"cm-brain-preview-{}-{}.brain",
|
||||
std::process::id(),
|
||||
safe
|
||||
));
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
let pulled = pull(reference, &tmp).await?;
|
||||
let b = ClawBrain::open_or_create(&tmp, reference)?;
|
||||
@@ -207,7 +229,10 @@ pub async fn preview(reference: &str) -> Result<BrainPreview, BrainError> {
|
||||
memory_count: b.memory_count(),
|
||||
memory_recent: b.recent_memory(4).into_iter().map(|(_, t)| t).collect(),
|
||||
runtime: b.runtime().map(|s| !s.trim().is_empty()).unwrap_or(false),
|
||||
provenance: b.provenance().map(|s| !s.trim().is_empty()).unwrap_or(false),
|
||||
provenance: b
|
||||
.provenance()
|
||||
.map(|s| !s.trim().is_empty())
|
||||
.unwrap_or(false),
|
||||
};
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
Ok(pv)
|
||||
@@ -225,13 +250,27 @@ pub async fn pull_merge(reference: &str, dest_brain: &Path) -> Result<PulledBrai
|
||||
let assembled = {
|
||||
let src = ClawBrain::open_or_create(&tmp, reference)?;
|
||||
let mut dst = ClawBrain::open_or_create(dest_brain, reference)?;
|
||||
if let Some(s) = src.system_prompt() { dst.set_system_prompt(&s)?; }
|
||||
if let Some(a) = src.agent_md() { dst.set_agent_md(&a)?; }
|
||||
if let Some(p) = src.personality() { dst.set_personality(&p)?; }
|
||||
for (n, b) in src.skills() { dst.set_skill(&n, &b)?; }
|
||||
for (n, st) in src.tools() { dst.set_tool(&n, &st)?; }
|
||||
if let Some(rt) = src.runtime() { let _ = dst.set_runtime(&rt); }
|
||||
for (_, text) in src.recent_memory(200) { let _ = dst.remember("memory", &text, "brain-apply"); }
|
||||
if let Some(s) = src.system_prompt() {
|
||||
dst.set_system_prompt(&s)?;
|
||||
}
|
||||
if let Some(a) = src.agent_md() {
|
||||
dst.set_agent_md(&a)?;
|
||||
}
|
||||
if let Some(p) = src.personality() {
|
||||
dst.set_personality(&p)?;
|
||||
}
|
||||
for (n, b) in src.skills() {
|
||||
dst.set_skill(&n, &b)?;
|
||||
}
|
||||
for (n, st) in src.tools() {
|
||||
dst.set_tool(&n, &st)?;
|
||||
}
|
||||
if let Some(rt) = src.runtime() {
|
||||
let _ = dst.set_runtime(&rt);
|
||||
}
|
||||
for (_, text) in src.recent_memory(200) {
|
||||
let _ = dst.remember("memory", &text, "brain-apply");
|
||||
}
|
||||
dst.assembled_identity()
|
||||
};
|
||||
let _ = std::fs::remove_file(&tmp);
|
||||
@@ -249,7 +288,11 @@ pub async fn push(
|
||||
description: &str,
|
||||
tags: &[String],
|
||||
) -> Result<(), BrainError> {
|
||||
if std::env::var("BRAINHUB_API_KEY").unwrap_or_default().trim().is_empty() {
|
||||
if std::env::var("BRAINHUB_API_KEY")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.is_empty()
|
||||
{
|
||||
return Err(BrainError::Backend(
|
||||
"BRAINHUB_API_KEY is not set — cannot push to ClawBrainHub".into(),
|
||||
));
|
||||
@@ -271,7 +314,11 @@ pub async fn whoami() -> Result<String, BrainError> {
|
||||
/// Delete a brain (all versions) from the registry. Requires `BRAINHUB_API_KEY`
|
||||
/// and ownership of the namespace.
|
||||
pub async fn delete(reference: &str) -> Result<(), BrainError> {
|
||||
if std::env::var("BRAINHUB_API_KEY").unwrap_or_default().trim().is_empty() {
|
||||
if std::env::var("BRAINHUB_API_KEY")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.is_empty()
|
||||
{
|
||||
return Err(BrainError::Backend("BRAINHUB_API_KEY not set".into()));
|
||||
}
|
||||
let client = BrainRegistryClient::new(config());
|
||||
@@ -377,8 +424,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
#[ignore = "hits live clawbrainhub.com"]
|
||||
async fn live_pull_general_assistant() {
|
||||
let dest =
|
||||
std::env::temp_dir().join(format!("cm-brain-pull-{}.brain", std::process::id()));
|
||||
let dest = std::env::temp_dir().join(format!("cm-brain-pull-{}.brain", std::process::id()));
|
||||
let _ = std::fs::remove_file(&dest);
|
||||
let pulled = pull("redclawsystems/general-assistant", &dest)
|
||||
.await
|
||||
@@ -400,19 +446,32 @@ mod tests {
|
||||
#[tokio::test]
|
||||
#[ignore = "hits live clawbrainhub.com"]
|
||||
async fn live_pull_merge_into_existing() {
|
||||
let dest = std::env::temp_dir().join(format!("cm-brain-merge-{}.brain", std::process::id()));
|
||||
let dest =
|
||||
std::env::temp_dir().join(format!("cm-brain-merge-{}.brain", std::process::id()));
|
||||
let _ = std::fs::remove_file(&dest);
|
||||
{
|
||||
let mut b = ClawBrain::open_or_create(&dest, "x").unwrap();
|
||||
b.set_skill("existing", "keep me").unwrap();
|
||||
}
|
||||
let pulled = pull_merge("redclawsystems/general-assistant", &dest).await.expect("merge");
|
||||
assert!(!pulled.system_prompt.is_empty(), "assembled identity returned");
|
||||
let pulled = pull_merge("redclawsystems/general-assistant", &dest)
|
||||
.await
|
||||
.expect("merge");
|
||||
assert!(
|
||||
!pulled.system_prompt.is_empty(),
|
||||
"assembled identity returned"
|
||||
);
|
||||
let b = ClawBrain::open_or_create(&dest, "x").unwrap();
|
||||
let names: Vec<String> = b.skills().into_iter().map(|(n, _)| n).collect();
|
||||
assert!(names.iter().any(|n| n == "existing"), "existing skill preserved; got {names:?}");
|
||||
assert!(
|
||||
names.iter().any(|n| n == "existing"),
|
||||
"existing skill preserved; got {names:?}"
|
||||
);
|
||||
assert!(names.len() > 1, "merged skills added; got {names:?}");
|
||||
eprintln!("merged → {} skills, {} memories", names.len(), b.memory_count());
|
||||
eprintln!(
|
||||
"merged → {} skills, {} memories",
|
||||
names.len(),
|
||||
b.memory_count()
|
||||
);
|
||||
let _ = std::fs::remove_file(&dest);
|
||||
}
|
||||
|
||||
@@ -420,9 +479,16 @@ mod tests {
|
||||
#[ignore = "hits live clawbrainhub.com"]
|
||||
async fn live_list() {
|
||||
let items = list("").await.expect("list");
|
||||
eprintln!("registry browse returned {} brains: {:?}", items.len(), items.iter().map(|b| &b.reference).collect::<Vec<_>>());
|
||||
eprintln!(
|
||||
"registry browse returned {} brains: {:?}",
|
||||
items.len(),
|
||||
items.iter().map(|b| &b.reference).collect::<Vec<_>>()
|
||||
);
|
||||
assert!(!items.is_empty(), "seed-browse should surface brains");
|
||||
assert!(items.iter().any(|b| b.reference == "omar/react-native"), "react-native should appear");
|
||||
assert!(
|
||||
items.iter().any(|b| b.reference == "omar/react-native"),
|
||||
"react-native should appear"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -436,8 +502,20 @@ mod tests {
|
||||
let sp = b.system_prompt().unwrap_or_default();
|
||||
let am = b.agent_md().unwrap_or_default();
|
||||
let pe = b.personality().unwrap_or_default();
|
||||
let sk = b.skills().into_iter().map(|(n, bd)| format!("## {n}\n{bd}")).collect::<Vec<_>>().join("\n\n");
|
||||
eprintln!("{r}: system_prompt={} agent_md={} persona={} skills_md={} chars (skills={})", sp.len(), am.len(), pe.len(), sk.len(), b.skills().len());
|
||||
let sk = b
|
||||
.skills()
|
||||
.into_iter()
|
||||
.map(|(n, bd)| format!("## {n}\n{bd}"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n");
|
||||
eprintln!(
|
||||
"{r}: system_prompt={} agent_md={} persona={} skills_md={} chars (skills={})",
|
||||
sp.len(),
|
||||
am.len(),
|
||||
pe.len(),
|
||||
sk.len(),
|
||||
b.skills().len()
|
||||
);
|
||||
let payload = format!("BRAIN: {r}\n\n=== SYSTEM PROMPT ===\n{sp}\n\n=== AGENTS.md ===\n{am}\n\n=== PERSONA ===\n{pe}\n\n=== SKILLS ===\n{sk}");
|
||||
std::fs::write("/tmp/brain-dump.txt", &payload).unwrap();
|
||||
eprintln!("wrote /tmp/brain-dump.txt ({} chars)", payload.len());
|
||||
@@ -447,7 +525,20 @@ mod tests {
|
||||
#[tokio::test]
|
||||
#[ignore = "hits live clawbrainhub.com — read-only scan"]
|
||||
async fn live_scan_empty_brains() {
|
||||
let queries = ["", "omar", "assistant", "default", "test", "claw", "agent", "brain", "react", "general", "data", "code"];
|
||||
let queries = [
|
||||
"",
|
||||
"omar",
|
||||
"assistant",
|
||||
"default",
|
||||
"test",
|
||||
"claw",
|
||||
"agent",
|
||||
"brain",
|
||||
"react",
|
||||
"general",
|
||||
"data",
|
||||
"code",
|
||||
];
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
for q in queries {
|
||||
for it in list(q).await.unwrap_or_default() {
|
||||
@@ -472,9 +563,15 @@ mod tests {
|
||||
async fn live_apply_react_native_hdf5() {
|
||||
let dest = std::env::temp_dir().join(format!("cm-brain-rn-{}.brain", std::process::id()));
|
||||
let _ = std::fs::remove_file(&dest);
|
||||
let pulled = pull_merge("omar/react-native", &dest).await.expect("merge HDF5 brain");
|
||||
let pulled = pull_merge("omar/react-native", &dest)
|
||||
.await
|
||||
.expect("merge HDF5 brain");
|
||||
let b = ClawBrain::open_or_create(&dest, "x").unwrap();
|
||||
eprintln!("react-native → system_prompt {} chars, {} skills", pulled.system_prompt.len(), b.skills().len());
|
||||
eprintln!(
|
||||
"react-native → system_prompt {} chars, {} skills",
|
||||
pulled.system_prompt.len(),
|
||||
b.skills().len()
|
||||
);
|
||||
let _ = std::fs::remove_file(&dest);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user