diff --git a/Cargo.lock b/Cargo.lock index 8a36059c..6c07357e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,179 +483,21 @@ dependencies = [ "wasip3", ] -[[package]] -name = "hammer-agent" -version = "0.0.1" -dependencies = [ - "anyhow", - "base64", - "hammer-core", - "hammer-journal", - "hammer-overlay", - "serde", - "serde_json", - "serde_yaml", - "tempfile", - "thiserror", - "tracing", - "ureq", -] - -[[package]] -name = "hammer-bootstrap" -version = "0.0.1" -dependencies = [ - "anyhow", - "hammer-build", - "hammer-core", - "hex", - "serde", - "serde_json", - "sha2", - "tempfile", - "thiserror", - "tracing", -] - -[[package]] -name = "hammer-build" -version = "0.0.1" -dependencies = [ - "anyhow", - "hammer-core", - "hex", - "libc", - "serde_json", - "sha2", - "tempfile", - "thiserror", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "hammer-cli" -version = "0.0.1" -dependencies = [ - "anyhow", - "base64", - "clap", - "hammer-agent", - "hammer-bootstrap", - "hammer-build", - "hammer-core", - "hammer-journal", - "hammer-mirror", - "hammer-overlay", - "hammer-upgrade", - "hex", - "nix", - "serde", - "serde_json", - "sha2", - "tempfile", - "toml", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "hammer-core" -version = "0.0.1" -dependencies = [ - "anyhow", - "base64", - "blake3", - "ed25519-dalek", - "getrandom 0.2.17", - "serde", - "serde_json", - "serde_yaml", - "tempfile", - "thiserror", - "toml", -] - -[[package]] -name = "hammer-journal" -version = "0.0.1" -dependencies = [ - "anyhow", - "blake3", - "hammer-core", - "serde", - "serde_json", - "tempfile", - "thiserror", - "tracing", -] - -[[package]] -name = "hammer-mirror" -version = "0.0.1" -dependencies = [ - "anyhow", - "hammer-core", - "serde", - "serde_json", - "tempfile", - "thiserror", - "tracing", -] - -[[package]] -name = "hammer-overlay" -version = "0.0.1" -dependencies = [ - "anyhow", - "hammer-core", - "hammer-journal", - "libc", - "serde", - "serde_json", - "tempfile", - "thiserror", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "hammer-recover" -version = "0.0.1" -dependencies = [ - "hammer-journal", - "hammer-upgrade", -] - -[[package]] -name = "hammer-upgrade" -version = "0.0.1" -dependencies = [ - "anyhow", - "hammer-core", - "hammer-journal", - "serde", - "serde_json", - "tempfile", - "thiserror", - "tracing", -] - [[package]] name = "hammerd" version = "0.0.1" dependencies = [ "anyhow", "clap", - "hammer-build", - "hammer-core", - "hammer-journal", - "hammer-overlay", "libc", "nix", "postcard", "serde", "serde_json", + "takana-build", + "takana-core", + "takana-journal", + "takana-overlay", "tempfile", "thiserror", "tracing", @@ -1381,6 +1223,164 @@ dependencies = [ "syn", ] +[[package]] +name = "takana-agent" +version = "0.0.1" +dependencies = [ + "anyhow", + "base64", + "serde", + "serde_json", + "serde_yaml", + "takana-core", + "takana-journal", + "takana-overlay", + "tempfile", + "thiserror", + "tracing", + "ureq", +] + +[[package]] +name = "takana-bootstrap" +version = "0.0.1" +dependencies = [ + "anyhow", + "hex", + "serde", + "serde_json", + "sha2", + "takana-build", + "takana-core", + "tempfile", + "thiserror", + "tracing", +] + +[[package]] +name = "takana-build" +version = "0.0.1" +dependencies = [ + "anyhow", + "hex", + "libc", + "serde_json", + "sha2", + "takana-core", + "tempfile", + "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "takana-cli" +version = "0.0.1" +dependencies = [ + "anyhow", + "base64", + "clap", + "hex", + "nix", + "serde", + "serde_json", + "sha2", + "takana-agent", + "takana-bootstrap", + "takana-build", + "takana-core", + "takana-journal", + "takana-mirror", + "takana-overlay", + "takana-upgrade", + "tempfile", + "toml", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "takana-core" +version = "0.0.1" +dependencies = [ + "anyhow", + "base64", + "blake3", + "ed25519-dalek", + "getrandom 0.2.17", + "serde", + "serde_json", + "serde_yaml", + "tempfile", + "thiserror", + "toml", +] + +[[package]] +name = "takana-journal" +version = "0.0.1" +dependencies = [ + "anyhow", + "blake3", + "serde", + "serde_json", + "takana-core", + "tempfile", + "thiserror", + "tracing", +] + +[[package]] +name = "takana-mirror" +version = "0.0.1" +dependencies = [ + "anyhow", + "serde", + "serde_json", + "takana-core", + "tempfile", + "thiserror", + "tracing", +] + +[[package]] +name = "takana-overlay" +version = "0.0.1" +dependencies = [ + "anyhow", + "libc", + "serde", + "serde_json", + "takana-core", + "takana-journal", + "tempfile", + "thiserror", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "takana-recover" +version = "0.0.1" +dependencies = [ + "takana-journal", + "takana-upgrade", +] + +[[package]] +name = "takana-upgrade" +version = "0.0.1" +dependencies = [ + "anyhow", + "serde", + "serde_json", + "takana-core", + "takana-journal", + "tempfile", + "thiserror", + "tracing", +] + [[package]] name = "tempfile" version = "3.27.0" diff --git a/Cargo.toml b/Cargo.toml index 9e43f201..302e1361 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,16 +1,16 @@ [workspace] resolver = "2" members = [ - "crates/hammer-core", - "crates/hammer-build", - "crates/hammer-bootstrap", - "crates/hammer-overlay", - "crates/hammer-journal", - "crates/hammer-mirror", - "crates/hammer-upgrade", - "crates/hammer-recover", - "crates/hammer-agent", - "crates/hammer-cli", + "crates/takana-core", + "crates/takana-build", + "crates/takana-bootstrap", + "crates/takana-overlay", + "crates/takana-journal", + "crates/takana-mirror", + "crates/takana-upgrade", + "crates/takana-recover", + "crates/takana-agent", + "crates/takana-cli", "crates/hammerd", "crates/netup", ] @@ -23,14 +23,14 @@ authors = ["sergio "] repository = "https://gitea.gioser.net/sergio/hammer" [workspace.dependencies] -hammer-core = { path = "crates/hammer-core" } -hammer-build = { path = "crates/hammer-build" } -hammer-bootstrap = { path = "crates/hammer-bootstrap" } -hammer-overlay = { path = "crates/hammer-overlay" } -hammer-journal = { path = "crates/hammer-journal" } -hammer-mirror = { path = "crates/hammer-mirror" } -hammer-upgrade = { path = "crates/hammer-upgrade" } -hammer-agent = { path = "crates/hammer-agent" } +takana-core = { path = "crates/takana-core" } +takana-build = { path = "crates/takana-build" } +takana-bootstrap = { path = "crates/takana-bootstrap" } +takana-overlay = { path = "crates/takana-overlay" } +takana-journal = { path = "crates/takana-journal" } +takana-mirror = { path = "crates/takana-mirror" } +takana-upgrade = { path = "crates/takana-upgrade" } +takana-agent = { path = "crates/takana-agent" } # shared third-party deps, pinned at the workspace level anyhow = "1" diff --git a/crates/hammerd/Cargo.toml b/crates/hammerd/Cargo.toml index 6e211c03..2f453254 100644 --- a/crates/hammerd/Cargo.toml +++ b/crates/hammerd/Cargo.toml @@ -12,10 +12,10 @@ name = "hammerd" path = "src/main.rs" [dependencies] -hammer-core.workspace = true -hammer-build.workspace = true -hammer-journal.workspace = true -hammer-overlay.workspace = true +takana-core.workspace = true +takana-build.workspace = true +takana-journal.workspace = true +takana-overlay.workspace = true anyhow.workspace = true clap.workspace = true thiserror.workspace = true diff --git a/crates/hammerd/src/bus.rs b/crates/hammerd/src/bus.rs index d22b605a..803ec0c7 100644 --- a/crates/hammerd/src/bus.rs +++ b/crates/hammerd/src/bus.rs @@ -25,7 +25,7 @@ use std::thread; use nix::sys::socket::{getsockopt, sockopt::PeerCredentials}; use crate::events::EventBus; -use hammer_core::proto::{ +use takana_core::proto::{ Cap, Command, Event, EvidenceCheckVerdict, EvidenceVerdict, Peer, RecipeInline, PROTOCOL_VERSION, }; @@ -49,7 +49,7 @@ pub fn default_policy() -> CapsPolicy { /// Política derivada de un fichero `agent-caps.toml` (SDD 07 §4). El peer no elige sus caps; /// las resuelve la config por `(uid, gid)`. -pub fn policy_from_config(cfg: hammer_core::AgentCapsConfig) -> CapsPolicy { +pub fn policy_from_config(cfg: takana_core::AgentCapsConfig) -> CapsPolicy { Arc::new(move |peer: &Peer| cfg.caps_for(peer.uid, peer.gid)) } @@ -259,7 +259,7 @@ fn dispatch( .ok(); } Command::Inject { artifact, target, overlay: _ } => { - let store = match hammer_core::Store::open(&ctx.store_root) { + let store = match takana_core::Store::open(&ctx.store_root) { Ok(s) => s, Err(e) => { let _ = tx.send(Event::Error { @@ -279,10 +279,10 @@ fn dispatch( return; } }; - let report = match hammer_build::run_hydrate( + let report = match takana_build::run_hydrate( &artifact_dir, Path::new(&target), - hammer_core::LinkMode::Static, + takana_core::LinkMode::Static, None, ) { Ok(r) => r, @@ -333,7 +333,7 @@ fn dispatch( // El daemon evalúa con el `fs_root` del sistema host (None ⇒ rutas // absolutas tal y como vienen). Si el .swm necesitara otra base, el // cliente puede evaluar localmente con un EvalContext distinto. - hammer_core::query::eval_str(e, &hammer_core::query::EvalContext::new()) + takana_core::query::eval_str(e, &takana_core::query::EvalContext::new()) } other => { let _ = tx.send(Event::Error { @@ -363,7 +363,7 @@ fn dispatch( fn run_compile(recipe: RecipeInline, store_root: PathBuf, tx: Sender) { let name = recipe.name.clone(); - let mutation = hammer_core::swm::Mutation::SourcePatch { + let mutation = takana_core::swm::Mutation::SourcePatch { repo: recipe.repo, commit: recipe.commit, tarball: recipe.tarball, @@ -371,7 +371,7 @@ fn run_compile(recipe: RecipeInline, store_root: PathBuf, tx: Sender) { strip_components: None, patch: recipe.patch, patch_url: None, - build: hammer_core::swm::SwmBuild { + build: takana_core::swm::SwmBuild { compiler: recipe.compiler, target: recipe.target, link: recipe.link, @@ -389,7 +389,7 @@ fn run_compile(recipe: RecipeInline, store_root: PathBuf, tx: Sender) { // de compatibilidad vive en `install` (CLI) contra el estado instalado. Vacío aquí. slots: Default::default(), }; - let store = match hammer_core::Store::open(&store_root) { + let store = match takana_core::Store::open(&store_root) { Ok(s) => s, Err(e) => { let _ = tx.send(Event::BuildFailed { @@ -400,8 +400,8 @@ fn run_compile(recipe: RecipeInline, store_root: PathBuf, tx: Sender) { return; } }; - let cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - match hammer_build::build_source_patch(&mutation, &cfg, &store, None, None) { + let cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + match takana_build::build_source_patch(&mutation, &cfg, &store, None, None) { Ok(h) => { // [H1c] El artefacto está sellado; ahora EJECUTAMOS la evidencia declarada y // adjuntamos el veredicto. El gate ("no proponer" si falla) vive en el orquestador @@ -417,7 +417,7 @@ fn run_compile(recipe: RecipeInline, store_root: PathBuf, tx: Sender) { Err(e) => { // Si el fallo trae la cola del log del lab, la separamos de la razón para que la // IA pueda leer el error real del compilador, no sólo el mensaje de Rust. - let (reason, log_tail) = match hammer_build::sandbox::BuildFailure::from_error(&e) { + let (reason, log_tail) = match takana_build::sandbox::BuildFailure::from_error(&e) { Some(bf) => (bf.reason.clone(), bf.log_tail.clone()), None => (e.to_string(), None), }; @@ -437,13 +437,13 @@ fn run_compile(recipe: RecipeInline, store_root: PathBuf, tx: Sender) { /// - `Some(all_passed=false, …)` sintético si la evidencia ni siquiera pudo ejecutarse (falta una /// build-dep, error de sandbox…): eso también debe bloquear la propuesta, no pasar en silencio. fn evidence_verdict( - mutation: &hammer_core::swm::Mutation, - cfg: &hammer_build::BuildConfig, - store: &hammer_core::Store, + mutation: &takana_core::swm::Mutation, + cfg: &takana_build::BuildConfig, + store: &takana_core::Store, ) -> Option { let has_evidence = matches!( mutation, - hammer_core::swm::Mutation::SourcePatch { evidence, .. } if !evidence.is_empty() + takana_core::swm::Mutation::SourcePatch { evidence, .. } if !evidence.is_empty() ); if !has_evidence { return None; @@ -456,7 +456,7 @@ fn evidence_verdict( all_passed: false, max_level: None, checks: vec![EvidenceCheckVerdict { - kind: hammer_core::EvidenceKind::CmdExit, + kind: takana_core::EvidenceKind::CmdExit, cmd: "".into(), passed: false, detail: format!("la evidencia no pudo ejecutarse: {e}"), @@ -467,14 +467,14 @@ fn evidence_verdict( } fn run_evidence_inner( - mutation: &hammer_core::swm::Mutation, - cfg: &hammer_build::BuildConfig, - store: &hammer_core::Store, -) -> hammer_core::Result { - let catalog_dir = hammer_build::swm_bridge::catalog_dir_for(cfg, None); + mutation: &takana_core::swm::Mutation, + cfg: &takana_build::BuildConfig, + store: &takana_core::Store, +) -> takana_core::Result { + let catalog_dir = takana_build::swm_bridge::catalog_dir_for(cfg, None); std::fs::create_dir_all(&catalog_dir)?; - let recipe = hammer_build::swm_bridge::recipe_from_source_patch(mutation, None, &catalog_dir)?; - let report = hammer_build::run_evidence(&recipe, cfg, store)?; + let recipe = takana_build::swm_bridge::recipe_from_source_patch(mutation, None, &catalog_dir)?; + let report = takana_build::run_evidence(&recipe, cfg, store)?; Ok(EvidenceVerdict { all_passed: report.all_passed(), max_level: report.max_level_passed(), @@ -510,7 +510,7 @@ fn query_file(path: &str) -> serde_json::Value { } fn query_artifact(store_root: &Path, hash: &str) -> serde_json::Value { - let store = match hammer_core::Store::open(store_root) { + let store = match takana_core::Store::open(store_root) { Ok(s) => s, Err(e) => return serde_json::json!({"error": e.to_string()}), }; @@ -552,7 +552,7 @@ mod tests { #[test] fn config_policy_resolves_by_uid_gid() { - let cfg = hammer_core::AgentCapsConfig::from_toml( + let cfg = takana_core::AgentCapsConfig::from_toml( r#" default = ["query"] [[rule]] diff --git a/crates/hammerd/src/crashes.rs b/crates/hammerd/src/crashes.rs index a6673823..b66ac43c 100644 --- a/crates/hammerd/src/crashes.rs +++ b/crates/hammerd/src/crashes.rs @@ -28,7 +28,7 @@ use std::sync::mpsc::Receiver; -use hammer_core::proto::Event; +use takana_core::proto::Event; use crate::events::EventBus; diff --git a/crates/hammerd/src/events.rs b/crates/hammerd/src/events.rs index 5da2365c..fd85c0d1 100644 --- a/crates/hammerd/src/events.rs +++ b/crates/hammerd/src/events.rs @@ -12,7 +12,7 @@ use std::sync::mpsc::{self, Receiver, Sender}; use std::sync::{Arc, Mutex}; -use hammer_core::proto::Event; +use takana_core::proto::Event; #[derive(Clone)] pub struct EventBus { @@ -58,7 +58,7 @@ impl EventBus { #[cfg(test)] mod tests { use super::*; - use hammer_core::proto::Event; + use takana_core::proto::Event; #[test] fn publish_reaches_all_subs() { diff --git a/crates/hammerd/src/main.rs b/crates/hammerd/src/main.rs index 1a40bb49..7316f266 100644 --- a/crates/hammerd/src/main.rs +++ b/crates/hammerd/src/main.rs @@ -33,7 +33,7 @@ struct Args { journal: String, /// Directorio raíz de overlays (para que el watcher pueda filtrar eventos bajo overlays /// activos). Default coincide con `hammer try`. - #[arg(long, default_value = hammer_overlay::DEFAULT_STATE_ROOT)] + #[arg(long, default_value = takana_overlay::DEFAULT_STATE_ROOT)] overlay_state_root: String, /// Directorios extra a vigilar; si vacío, usa los defaults del FHS (SDD 05 §2). #[arg(long = "watch")] @@ -97,7 +97,7 @@ fn main() -> anyhow::Result<()> { // Watcher fanotify: opcional. Si falla (no caps), el daemon sigue con el bus solo. if !args.no_watcher { - let journal = hammer_journal::Journal::open(&args.journal)?; + let journal = takana_journal::Journal::open(&args.journal)?; let mut dirs = watcher::default_watch_dirs(); dirs.extend(args.extra_watch.clone()); let overlay_root = PathBuf::from(&args.overlay_state_root); @@ -132,7 +132,7 @@ fn main() -> anyhow::Result<()> { // Bus de agente: bloqueante en este thread. Si falla, fin del daemon. // Política de caps: del fichero si existe, si no la heurística por-UID por defecto. - let policy = match hammer_core::AgentCapsConfig::load(&args.agent_caps) { + let policy = match takana_core::AgentCapsConfig::load(&args.agent_caps) { Ok(Some(cfg)) => { tracing::info!(path = %args.agent_caps.display(), rules = cfg.rule.len(), "bus: política de caps cargada de fichero"); diff --git a/crates/hammerd/src/watcher.rs b/crates/hammerd/src/watcher.rs index da5e29ff..f451fc60 100644 --- a/crates/hammerd/src/watcher.rs +++ b/crates/hammerd/src/watcher.rs @@ -6,7 +6,7 @@ //! * Marcamos como `FAN_MARK_ADD | FAN_MARK_ONLYDIR` cada directorio vigilado. La cobertura //! por defecto (ver `default_watch_dirs`) cubre el FHS clásico de userland. //! * Filtro mínimo: ignoramos eventos cuya ruta resuelta cae dentro de un overlay activo -//! (consultamos `hammer_overlay::status` en cada batch — para Fase 3 el coste es +//! (consultamos `takana_overlay::status` en cada batch — para Fase 3 el coste es //! despreciable; cuando los overlays se vuelvan numerosos cachearemos los paths). //! * Cada evento se materializa como `MutationEvent` con `source = External` y la `op` //! se deriva (`classify_op`): si el fd resuelve a un path borrado (`" (deleted)"`) es @@ -27,7 +27,7 @@ use std::os::fd::AsFd; use std::os::unix::ffi::OsStringExt; use std::path::{Path, PathBuf}; -use hammer_journal::{Actor, Journal, MutationEvent, MutationOp, Source}; +use takana_journal::{Actor, Journal, MutationEvent, MutationOp, Source}; use nix::fcntl::AT_FDCWD; use nix::sys::fanotify::{EventFFlags, Fanotify, InitFlags, MarkFlags, MaskFlags}; @@ -48,7 +48,7 @@ pub enum Error { #[error("read_events: {0}")] Read(nix::errno::Errno), #[error("journal: {0}")] - Journal(#[from] hammer_journal::Error), + Journal(#[from] takana_journal::Error), #[error("io: {0}")] Io(#[from] std::io::Error), } @@ -160,7 +160,7 @@ impl Watcher { let content_hash = if deleted { None } else { - match hammer_journal::hash_file(&path) { + match takana_journal::hash_file(&path) { Ok(h) => h, Err(e) => { tracing::warn!(path = %path.display(), error = %e, "watcher: no pude hashear contenido"); @@ -170,7 +170,7 @@ impl Watcher { }; let op = self.classify_op(&path, deleted)?; let me = MutationEvent { - ts: hammer_journal::now_rfc3339(), + ts: takana_journal::now_rfc3339(), op, path, by: Actor { @@ -188,7 +188,7 @@ impl Watcher { } recorded += 1; if let Some(bus) = &self.events { - bus.publish(&hammer_core::proto::Event::Modified { + bus.publish(&takana_core::proto::Event::Modified { path: me.path.display().to_string(), op: me.op.as_str().to_string(), ts: me.ts.clone(), @@ -216,7 +216,7 @@ impl Watcher { let Some(root) = &self.overlay_state_root else { return Vec::new(); }; - match hammer_overlay::status(root) { + match takana_overlay::status(root) { Ok(overlays) => overlays .into_iter() .flat_map(|o| o.mounts.into_iter().map(|m| m.target)) @@ -301,7 +301,7 @@ mod tests { fn me(op: MutationOp, path: &str, hash: Option<&str>) -> MutationEvent { MutationEvent { - ts: hammer_journal::now_rfc3339(), + ts: takana_journal::now_rfc3339(), op, path: PathBuf::from(path), by: Actor { source: Source::External, pid: Some(1), uid: Some(0) }, diff --git a/crates/hammerd/tests/arje_link_e2e.rs b/crates/hammerd/tests/arje_link_e2e.rs index 725d18b9..e7cbce14 100644 --- a/crates/hammerd/tests/arje_link_e2e.rs +++ b/crates/hammerd/tests/arje_link_e2e.rs @@ -24,7 +24,7 @@ use std::path::PathBuf; use std::thread; use std::time::Duration; -use hammer_core::proto::Event; +use takana_core::proto::Event; use serde::Serialize; use ulid::Ulid; diff --git a/crates/hammerd/tests/bus_e2e.rs b/crates/hammerd/tests/bus_e2e.rs index 2209955a..1eae79bb 100644 --- a/crates/hammerd/tests/bus_e2e.rs +++ b/crates/hammerd/tests/bus_e2e.rs @@ -23,7 +23,7 @@ use std::sync::Arc; use std::thread; use std::time::Duration; -use hammer_core::proto::{Cap, Command, Event, Peer, RecipeInline}; +use takana_core::proto::{Cap, Command, Event, Peer, RecipeInline}; /// Helper: lanza un bus en background y devuelve la ruta del socket. Limpia al final del /// test gracias al `tempfile::TempDir` que se le pasa al caller. diff --git a/crates/hammer-agent/Cargo.toml b/crates/takana-agent/Cargo.toml similarity index 87% rename from crates/hammer-agent/Cargo.toml rename to crates/takana-agent/Cargo.toml index e05c9ec7..0da3f9ac 100644 --- a/crates/hammer-agent/Cargo.toml +++ b/crates/takana-agent/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-agent" +name = "takana-agent" version.workspace = true edition.workspace = true license.workspace = true @@ -14,8 +14,8 @@ default = [] llm-claude = ["dep:ureq"] [dependencies] -hammer-core.workspace = true -hammer-overlay.workspace = true +takana-core.workspace = true +takana-overlay.workspace = true anyhow.workspace = true thiserror.workspace = true serde.workspace = true @@ -26,5 +26,5 @@ ureq = { version = "2", optional = true, default-features = false, features = [" [dev-dependencies] tempfile.workspace = true -hammer-journal.workspace = true +takana-journal.workspace = true base64.workspace = true diff --git a/crates/hammer-agent/src/client.rs b/crates/takana-agent/src/client.rs similarity index 97% rename from crates/hammer-agent/src/client.rs rename to crates/takana-agent/src/client.rs index b01145e7..8d0a531b 100644 --- a/crates/hammer-agent/src/client.rs +++ b/crates/takana-agent/src/client.rs @@ -17,7 +17,7 @@ use std::sync::{Arc, Condvar, Mutex}; use std::thread; use std::time::{Duration, Instant}; -use hammer_core::proto::{Cap, Command, Event, Peer, RecipeInline}; +use takana_core::proto::{Cap, Command, Event, Peer, RecipeInline}; #[derive(Debug, thiserror::Error)] pub enum ClientError { @@ -49,7 +49,7 @@ pub struct Welcome { #[derive(Debug, Clone)] pub struct CompileOutcome { pub artifact: String, - pub verdict: Option, + pub verdict: Option, } /// Estado compartido entre el reader thread y el caller. @@ -111,7 +111,7 @@ impl AgentClient { }, }; me.send(&Command::Hello { - ver: hammer_core::proto::PROTOCOL_VERSION, + ver: takana_core::proto::PROTOCOL_VERSION, client: client.to_string(), })?; let ev = me.recv_pending(Duration::from_secs(5))?; @@ -182,7 +182,7 @@ impl AgentClient { } /// Evalúa una expresión del mini-lenguaje (`bin:grep`, `pin:musl`, …) en el daemon. - /// El JSON devuelto sigue el schema de `hammer_core::query::eval`. + /// El JSON devuelto sigue el schema de `takana_core::query::eval`. pub fn query_expr(&mut self, expr: &str, timeout: Duration) -> Result { self.send(&Command::Query { what: "expr".into(), diff --git a/crates/hammer-agent/src/lib.rs b/crates/takana-agent/src/lib.rs similarity index 93% rename from crates/hammer-agent/src/lib.rs rename to crates/takana-agent/src/lib.rs index 4f0355b3..6d8bb1b7 100644 --- a/crates/hammer-agent/src/lib.rs +++ b/crates/takana-agent/src/lib.rs @@ -38,11 +38,11 @@ pub enum Error { #[error("io: {0}")] Io(#[from] std::io::Error), #[error("overlay: {0}")] - Overlay(#[from] hammer_overlay::Error), + Overlay(#[from] takana_overlay::Error), #[error("apply: {0}")] - Apply(#[from] hammer_core::apply::ApplyError), + Apply(#[from] takana_core::apply::ApplyError), #[error("core: {0}")] - Core(#[from] hammer_core::Error), + Core(#[from] takana_core::Error), } pub type Result = std::result::Result; diff --git a/crates/hammer-agent/src/orchestrator.rs b/crates/takana-agent/src/orchestrator.rs similarity index 97% rename from crates/hammer-agent/src/orchestrator.rs rename to crates/takana-agent/src/orchestrator.rs index 1cc8eada..5d55249f 100644 --- a/crates/hammer-agent/src/orchestrator.rs +++ b/crates/takana-agent/src/orchestrator.rs @@ -7,7 +7,7 @@ //! schema → swm.verify_schema() //! base → swm.verify_base(local) → debe ser Ok //! build → para cada source_patch: AgentClient.compile() vía el bus (o saltar si --no-bus) -//! try → hammer_overlay::try_overlay() (o usar --prefix) +//! try → takana_overlay::try_overlay() (o usar --prefix) //! apply → hammer-core::apply para config_edit/file_drop + hydrate para source_patch //! verify → spot-checks post-condición sobre disco //! propose → devuelve Proposal con overlay_id + log de checks @@ -18,11 +18,11 @@ use std::path::{Path, PathBuf}; use std::time::Duration; -use hammer_core::apply::{apply_config_edit, apply_file_drop, rebase_path}; -use hammer_core::proto::RecipeInline; -use hammer_core::swm::{Mutation, Swm}; -use hammer_core::BaseRef; -use hammer_overlay::OverlayId; +use takana_core::apply::{apply_config_edit, apply_file_drop, rebase_path}; +use takana_core::proto::RecipeInline; +use takana_core::swm::{Mutation, Swm}; +use takana_core::BaseRef; +use takana_overlay::OverlayId; use crate::client::AgentClient; use crate::translator::{IntentTranslator, SystemContext}; @@ -79,7 +79,7 @@ impl Orchestrator { // 3. BASE match swm.verify_base(&self.base) { - hammer_core::BaseCompat::Ok => {} + takana_core::BaseCompat::Ok => {} other => { return Err(Error::Orchestrate(format!( "base incompatible: {other:?}" @@ -91,7 +91,7 @@ impl Orchestrator { let (overlay_id, prefix): (Option, Option) = match &self.apply { ApplyTarget::Overlay { state_root } => { std::fs::create_dir_all(state_root)?; - let id = hammer_overlay::try_overlay(&[], state_root)?; + let id = takana_overlay::try_overlay(&[], state_root)?; (Some(id), None) } ApplyTarget::Prefix { prefix } => { @@ -147,8 +147,8 @@ impl Orchestrator { } Mutation::InitRule { action, service, command } => { let rules_dir = - rebase_path(hammer_core::apply::INIT_RULES_DIR, prefix.as_deref()); - let p = hammer_core::apply::apply_init_rule( + rebase_path(takana_core::apply::INIT_RULES_DIR, prefix.as_deref()); + let p = takana_core::apply::apply_init_rule( &rules_dir, action, service, command, ) .map_err(|e| Error::Orchestrate(format!("init_rule '{action} {service}': {e}")))?; @@ -246,7 +246,7 @@ impl Orchestrator { // Hidratamos localmente desde el store (sin pasar por el bus, evita un // segundo Inject que duplicaría trabajo). - let store = hammer_core::Store::open(store)?; + let store = takana_core::Store::open(store)?; let artifact_dir = store .find_by_hash(&artifact) .map_err(|e| Error::Orchestrate(format!("find_by_hash: {e}")))?; @@ -340,13 +340,13 @@ fn wait_for_crash(policy: &RepairPolicy) -> Option { let deadline = std::time::Instant::now() + policy.crash_window; // Drenamos primero la cola asíncrona ya acumulada (eventos llegados durante el `run`). for ev in client.drain_async() { - if let hammer_core::proto::Event::Crashed { service, code } = ev { + if let takana_core::proto::Event::Crashed { service, code } = ev { return Some(CrashInfo { service, code }); } } while let Some(remaining) = deadline.checked_duration_since(std::time::Instant::now()) { match client.next_async(remaining) { - Ok(hammer_core::proto::Event::Crashed { service, code }) => { + Ok(takana_core::proto::Event::Crashed { service, code }) => { return Some(CrashInfo { service, code }); } Ok(_other) => continue, @@ -554,7 +554,7 @@ impl Default for RepairPolicy { mod tests { use super::*; use crate::translator::MockTranslator; - use hammer_core::swm::{Base, Mutation}; + use takana_core::swm::{Base, Mutation}; use std::collections::BTreeMap; fn baseref() -> BaseRef { @@ -626,7 +626,7 @@ mod tests { strip_components: None, patch: None, patch_url: None, - build: hammer_core::swm::SwmBuild { + build: takana_core::swm::SwmBuild { compiler: "zig-cc".into(), target: "x86_64-linux-musl".into(), link: "static".into(), diff --git a/crates/hammer-agent/src/translator.rs b/crates/takana-agent/src/translator.rs similarity index 99% rename from crates/hammer-agent/src/translator.rs rename to crates/takana-agent/src/translator.rs index f334075c..0b7f5982 100644 --- a/crates/hammer-agent/src/translator.rs +++ b/crates/takana-agent/src/translator.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; use std::path::Path; -use hammer_core::{BaseRef, Swm}; +use takana_core::{BaseRef, Swm}; #[derive(Debug, thiserror::Error)] pub enum TranslateError { @@ -165,7 +165,7 @@ impl IntentTranslator for MockTranslator { #[cfg(test)] mod tests { use super::*; - use hammer_core::swm::{Base, Mutation}; + use takana_core::swm::{Base, Mutation}; use std::collections::BTreeMap; fn empty_ctx() -> SystemContext { diff --git a/crates/hammer-agent/src/translator_claude.rs b/crates/takana-agent/src/translator_claude.rs similarity index 99% rename from crates/hammer-agent/src/translator_claude.rs rename to crates/takana-agent/src/translator_claude.rs index 7a033ff6..f2118456 100644 --- a/crates/hammer-agent/src/translator_claude.rs +++ b/crates/takana-agent/src/translator_claude.rs @@ -31,7 +31,7 @@ //! ``` use crate::translator::{IntentTranslator, SystemContext, TranslateError}; -use hammer_core::Swm; +use takana_core::Swm; /// Inyección HTTP. La implementación por defecto ([`UreqHttp`]) usa `ureq` síncrono; /// los tests pasan una fake. @@ -279,7 +279,7 @@ mod tests { use std::collections::BTreeMap; use std::sync::{Arc, Mutex}; - use hammer_core::BaseRef; + use takana_core::BaseRef; /// Fake HTTP que captura el request y devuelve un body pre-armado. struct FakeHttp { diff --git a/crates/hammer-agent/tests/ai_loop_e2e.rs b/crates/takana-agent/tests/ai_loop_e2e.rs similarity index 96% rename from crates/hammer-agent/tests/ai_loop_e2e.rs rename to crates/takana-agent/tests/ai_loop_e2e.rs index 0a39135c..6aa06206 100644 --- a/crates/hammer-agent/tests/ai_loop_e2e.rs +++ b/crates/takana-agent/tests/ai_loop_e2e.rs @@ -11,12 +11,12 @@ use std::collections::BTreeMap; use base64::{engine::general_purpose::STANDARD, Engine as _}; -use hammer_agent::{ +use takana_agent::{ orchestrator::{ApplyTarget, CompileMode}, MockTranslator, Orchestrator, }; -use hammer_core::swm::{Base, Mutation, Swm}; -use hammer_core::{ArtifactHash, BaseRef}; +use takana_core::swm::{Base, Mutation, Swm}; +use takana_core::{ArtifactHash, BaseRef}; fn baseref() -> BaseRef { let mut pins = BTreeMap::new(); @@ -86,7 +86,7 @@ fn intent_to_overlay_proposal_via_mock_translator() { proposal .checks .iter() - .all(|c| matches!(c.level, hammer_agent::orchestrator::CheckLevel::Pass)), + .all(|c| matches!(c.level, takana_agent::orchestrator::CheckLevel::Pass)), "todas las checks deben pasar" ); diff --git a/crates/hammer-agent/tests/client_against_stub_bus.rs b/crates/takana-agent/tests/client_against_stub_bus.rs similarity index 93% rename from crates/hammer-agent/tests/client_against_stub_bus.rs rename to crates/takana-agent/tests/client_against_stub_bus.rs index 80f3881a..9d630519 100644 --- a/crates/hammer-agent/tests/client_against_stub_bus.rs +++ b/crates/takana-agent/tests/client_against_stub_bus.rs @@ -10,7 +10,7 @@ use std::path::PathBuf; use std::thread; use std::time::Duration; -use hammer_core::proto::{Cap, Command, Event, Peer, RecipeInline, PROTOCOL_VERSION}; +use takana_core::proto::{Cap, Command, Event, Peer, RecipeInline, PROTOCOL_VERSION}; fn start_stub_bus(sock: PathBuf) -> std::sync::mpsc::Sender { let (tx_async, rx_async) = std::sync::mpsc::channel::(); @@ -86,14 +86,14 @@ fn stub_serve(stream: UnixStream, rx_async: std::sync::mpsc::Receiver) { // El stub refleja la evidencia declarada como un veredicto "todo pasa" para // ejercitar el camino H1c del cliente (sin lab real que la ejecute). let verdict = (!recipe.evidence.is_empty()).then(|| { - hammer_core::proto::EvidenceVerdict { + takana_core::proto::EvidenceVerdict { all_passed: true, max_level: recipe.evidence.checks.iter().map(|c| c.kind).max(), checks: recipe .evidence .checks .iter() - .map(|c| hammer_core::proto::EvidenceCheckVerdict { + .map(|c| takana_core::proto::EvidenceCheckVerdict { kind: c.kind, cmd: c.cmd.clone(), passed: true, @@ -152,7 +152,7 @@ fn client_handshake_compile_and_async_modified() { thread::sleep(Duration::from_millis(10)); } - let mut client = hammer_agent::AgentClient::connect(&sock).expect("connect"); + let mut client = takana_agent::AgentClient::connect(&sock).expect("connect"); assert_eq!(client.welcome.ver, PROTOCOL_VERSION); assert!(client.welcome.caps.contains(&Cap::Compile)); @@ -167,9 +167,9 @@ fn client_handshake_compile_and_async_modified() { target: "x86_64-linux-musl".into(), link: "static".into(), flags: vec![], - evidence: hammer_core::Evidence { - checks: vec![hammer_core::EvidenceCheck { - kind: hammer_core::EvidenceKind::CmdExit, + evidence: takana_core::Evidence { + checks: vec![takana_core::EvidenceCheck { + kind: takana_core::EvidenceKind::CmdExit, cmd: "grep --version".into(), expected_exit: 0, expected_output: None, @@ -184,7 +184,7 @@ fn client_handshake_compile_and_async_modified() { let verdict = outcome.verdict.expect("verdict presente (declaramos evidencia)"); assert!(verdict.all_passed); assert_eq!(verdict.checks.len(), 1); - assert_eq!(verdict.max_level, Some(hammer_core::EvidenceKind::CmdExit)); + assert_eq!(verdict.max_level, Some(takana_core::EvidenceKind::CmdExit)); // El stub también puede empujar eventos asíncronos. Inyectamos un Modified y vemos // que el cliente lo entrega por drain_async()/next_async(). diff --git a/crates/hammer-agent/tests/orchestrator_evidence_gate.rs b/crates/takana-agent/tests/orchestrator_evidence_gate.rs similarity index 95% rename from crates/hammer-agent/tests/orchestrator_evidence_gate.rs rename to crates/takana-agent/tests/orchestrator_evidence_gate.rs index 9434d66b..f5831b9c 100644 --- a/crates/hammer-agent/tests/orchestrator_evidence_gate.rs +++ b/crates/takana-agent/tests/orchestrator_evidence_gate.rs @@ -10,13 +10,13 @@ use std::path::PathBuf; use std::thread; use std::time::Duration; -use hammer_agent::orchestrator::{ApplyTarget, CompileMode, Orchestrator}; -use hammer_agent::MockTranslator; -use hammer_core::proto::{ +use takana_agent::orchestrator::{ApplyTarget, CompileMode, Orchestrator}; +use takana_agent::MockTranslator; +use takana_core::proto::{ Cap, Command, Event, EvidenceCheckVerdict, EvidenceVerdict, Peer, PROTOCOL_VERSION, }; -use hammer_core::swm::{Base, Mutation, Swm, SwmBuild}; -use hammer_core::{BaseRef, Evidence, EvidenceCheck, EvidenceKind}; +use takana_core::swm::{Base, Mutation, Swm, SwmBuild}; +use takana_core::{BaseRef, Evidence, EvidenceCheck, EvidenceKind}; use std::collections::BTreeMap; /// Bus stub que responde a `Compile` con `BuildReady` cuyo veredicto tiene `all_passed=false`. diff --git a/crates/hammer-agent/tests/repair_loop.rs b/crates/takana-agent/tests/repair_loop.rs similarity index 96% rename from crates/hammer-agent/tests/repair_loop.rs rename to crates/takana-agent/tests/repair_loop.rs index 1bb899b8..2cede8f8 100644 --- a/crates/hammer-agent/tests/repair_loop.rs +++ b/crates/takana-agent/tests/repair_loop.rs @@ -11,12 +11,12 @@ use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; -use hammer_core::proto::{Cap, Command, Event, Peer, PROTOCOL_VERSION}; -use hammer_core::swm::{Base, Mutation}; -use hammer_core::{BaseRef, Swm}; +use takana_core::proto::{Cap, Command, Event, Peer, PROTOCOL_VERSION}; +use takana_core::swm::{Base, Mutation}; +use takana_core::{BaseRef, Swm}; -use hammer_agent::orchestrator::{ApplyTarget, CompileMode, RepairPolicy}; -use hammer_agent::{MockTranslator, Orchestrator}; +use takana_agent::orchestrator::{ApplyTarget, CompileMode, RepairPolicy}; +use takana_agent::{MockTranslator, Orchestrator}; /// El plan por conexión: lista de eventos a empujar tras el Welcome. El stub itera /// por las conexiones en orden y consume un slot del plan por cada una. @@ -112,7 +112,7 @@ fn swm_touch(path: &str) -> Swm { mutations: vec![Mutation::FileDrop { path: path.into(), // hash de "X" (un byte 0x58) — calculado con BLAKE3. - content_hash: hammer_core::ArtifactHash::of_inputs(&[b"X"]).as_str().to_string(), + content_hash: takana_core::ArtifactHash::of_inputs(&[b"X"]).as_str().to_string(), content_b64: Some("WA==".into()), content_url: None, }], diff --git a/crates/hammer-bootstrap/Cargo.toml b/crates/takana-bootstrap/Cargo.toml similarity index 84% rename from crates/hammer-bootstrap/Cargo.toml rename to crates/takana-bootstrap/Cargo.toml index 3a1db0a0..6e90a8dd 100644 --- a/crates/hammer-bootstrap/Cargo.toml +++ b/crates/takana-bootstrap/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-bootstrap" +name = "takana-bootstrap" version.workspace = true edition.workspace = true license.workspace = true @@ -8,8 +8,8 @@ repository.workspace = true description = "Bootstrap from-scratch de hammer: Stage 0/1/2 hacia el auto-alojamiento (SDD 11)." [dependencies] -hammer-core.workspace = true -hammer-build.workspace = true +takana-core.workspace = true +takana-build.workspace = true anyhow.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/hammer-bootstrap/src/lib.rs b/crates/takana-bootstrap/src/lib.rs similarity index 98% rename from crates/hammer-bootstrap/src/lib.rs rename to crates/takana-bootstrap/src/lib.rs index bde1d404..b13ddb88 100644 --- a/crates/hammer-bootstrap/src/lib.rs +++ b/crates/takana-bootstrap/src/lib.rs @@ -17,8 +17,8 @@ pub mod manifest; use std::path::{Path, PathBuf}; use std::process::Command; -use hammer_build::download; -use hammer_core::{ArtifactHash, Recipe, Store}; +use takana_build::download; +use takana_core::{ArtifactHash, Recipe, Store}; pub use manifest::{BootstrapManifest, StageEntry}; @@ -27,7 +27,7 @@ pub enum Error { #[error("io: {0}")] Io(#[from] std::io::Error), #[error("core: {0}")] - Core(#[from] hammer_core::Error), + Core(#[from] takana_core::Error), #[error("tar -x de la semilla falló (exit {0:?})")] Untar(Option), #[error("bootstrap: {0}")] @@ -147,17 +147,17 @@ fn locate_tool_dir(base: &Path, tool: &str) -> Result { } } -/// Deriva una [`hammer_build::BuildConfig`] desde `base` cuyo `zig_dir` apunta a la **semilla +/// Deriva una [`takana_build::BuildConfig`] desde `base` cuyo `zig_dir` apunta a la **semilla /// sellada** en vez del toolchain del host: así las recetas del Stage 1 cross-compilan con el /// toolchain fijado por hash (`seed_hash`), no con el `.dev-fs/tools/zig` de desarrollo. El resto /// de la config (rootfs, work, cache) se hereda intacto. pub fn seed_build_config( - base: &hammer_build::BuildConfig, + base: &takana_build::BuildConfig, seed: &SeedSpec, store: &Store, -) -> Result { +) -> Result { let zig_dir = seed.toolchain_dir(store)?; - Ok(hammer_build::BuildConfig { zig_dir, ..base.clone() }) + Ok(takana_build::BuildConfig { zig_dir, ..base.clone() }) } /// Hash de un rootfs sellado por Stage 1. Es un `ArtifactHash` derivado del **contenido lógico** @@ -265,15 +265,15 @@ pub struct Stage1Spec { /// /// Idempotente: si el rootfs (mismo hash de contenido) ya está sellado, no reconstruye. El /// cross-compile real requiere el rootfs base + toolchain del lab; en una máquina sin `.dev-fs` -/// `hammer_build::build` falla limpio antes de ensamblar nada. +/// `takana_build::build` falla limpio antes de ensamblar nada. pub fn stage1( spec: &Stage1Spec, - base_cfg: &hammer_build::BuildConfig, + base_cfg: &takana_build::BuildConfig, store: &Store, ) -> Result { // Toolchain = la semilla sellada, no el zig del host. let zig_dir = seed_toolchain_dir(store, &spec.seed_hash, spec.seed_kind)?; - let cfg = hammer_build::BuildConfig { zig_dir, ..base_cfg.clone() }; + let cfg = takana_build::BuildConfig { zig_dir, ..base_cfg.clone() }; // 1) Construir cada componente (cacheado por el lab si ya existe). let mut components: Vec<(String, ArtifactHash)> = Vec::with_capacity(STAGE1_COMPONENTS.len()); @@ -282,7 +282,7 @@ pub fn stage1( let recipe = Recipe::load_from_path(&recipe_path).map_err(|e| { Error::Other(format!("receta '{name}' ({}): {e}", recipe_path.display())) })?; - let h = hammer_build::build(&recipe, &cfg, store)?; + let h = takana_build::build(&recipe, &cfg, store)?; components.push((name.to_string(), h)); } @@ -367,7 +367,7 @@ fn assemble_rootfs( // Cada componente se proyecta al rootfs por hardlink (mismo store, mismo filesystem). for (name, h) in components { let dir = store.path_of(h, name); - hammer_build::run_hydrate(&dir, staging, hammer_core::LinkMode::Static, None)?; + takana_build::run_hydrate(&dir, staging, takana_core::LinkMode::Static, None)?; } // El sidecar de provenance de cada receta (`.hammer/recipe.toml`) no pertenece al rootfs @@ -605,14 +605,14 @@ fn assemble_product_rootfs( base_dir.display() ))); } - hammer_build::run_hydrate(&base_dir, staging, hammer_core::LinkMode::Static, None)?; + takana_build::run_hydrate(&base_dir, staging, takana_core::LinkMode::Static, None)?; // 2) userland Rust + servicios ENCIMA (hardlink). El userland va DESPUÉS de la base: sus symlinks // en /usr/bin reemplazan a los de busybox (run_hydrate sustituye el symlink existente) ⇒ el // producto corre las tools Rust. Orden userland→servicios (sin colisiones entre sí). for (name, h) in userland.iter().chain(services.iter()) { let dir = store.path_of(h, name); - hammer_build::run_hydrate(&dir, staging, hammer_core::LinkMode::Static, None)?; + takana_build::run_hydrate(&dir, staging, takana_core::LinkMode::Static, None)?; } let _ = std::fs::remove_dir_all(staging.join(".hammer")); @@ -681,7 +681,7 @@ fn assemble_product_rootfs( fn build_components( names: &[&str], recipes_dir: &Path, - cfg: &hammer_build::BuildConfig, + cfg: &takana_build::BuildConfig, store: &Store, ) -> Result> { let mut out = Vec::with_capacity(names.len()); @@ -690,7 +690,7 @@ fn build_components( let recipe = Recipe::load_from_path(&recipe_path).map_err(|e| { Error::Other(format!("receta '{name}' ({}): {e}", recipe_path.display())) })?; - let h = hammer_build::build(&recipe, cfg, store)?; + let h = takana_build::build(&recipe, cfg, store)?; out.push((name.to_string(), h)); } Ok(out) @@ -703,7 +703,7 @@ fn build_components( /// semilla): cada componente usa su `zig_version` propia, y si ya está sellado sale cacheado. pub fn product( base: &RootfsHash, - base_cfg: &hammer_build::BuildConfig, + base_cfg: &takana_build::BuildConfig, recipes_dir: &Path, store: &Store, ) -> Result { @@ -725,7 +725,7 @@ pub fn product_from_repo( base: &RootfsHash, repo_dir: &Path, trust_dir: &Path, - base_cfg: &hammer_build::BuildConfig, + base_cfg: &takana_build::BuildConfig, store: &Store, ) -> Result { // 1) userland + servicios REPRODUCIDOS desde el repo firmado (mismo shape que build_components). @@ -780,10 +780,10 @@ pub fn install_components_from_repo( names: &[&str], repo_dir: &Path, trust_dir: &Path, - cfg: &hammer_build::BuildConfig, + cfg: &takana_build::BuildConfig, store: &Store, ) -> Result> { - use hammer_core::{RepoIndex, SigStatus, TrustStore}; + use takana_core::{RepoIndex, SigStatus, TrustStore}; let index = RepoIndex::load(repo_dir)?; // Firma del release: exigimos TRUSTED. Un release no firmado / con clave desconocida / con firma @@ -801,7 +801,7 @@ pub fn install_components_from_repo( } } - let catalog_dir = hammer_build::swm_bridge::catalog_dir_for(cfg, None); + let catalog_dir = takana_build::swm_bridge::catalog_dir_for(cfg, None); std::fs::create_dir_all(&catalog_dir)?; let mut out = Vec::with_capacity(names.len()); @@ -817,7 +817,7 @@ pub fn install_components_from_repo( let mutation = source_patch_of(&dep_swm).ok_or_else(|| { Error::Other(format!("la dep '{}' no es un paquete source_patch", dep.name)) })?; - let dep_recipe = hammer_build::swm_bridge::recipe_from_source_patch( + let dep_recipe = takana_build::swm_bridge::recipe_from_source_patch( mutation, Some(&dep.name), &catalog_dir, @@ -829,7 +829,7 @@ pub fn install_components_from_repo( let mutation = source_patch_of(&swm).ok_or_else(|| { Error::Other(format!("'{name}' no es un paquete source_patch")) })?; - let hash = hammer_build::swm_bridge::build_source_patch(mutation, cfg, store, None, Some(name))?; + let hash = takana_build::swm_bridge::build_source_patch(mutation, cfg, store, None, Some(name))?; tracing::info!(%name, %hash, "product: componente reproducido desde el repo firmado"); out.push((name.to_string(), hash)); } @@ -837,18 +837,18 @@ pub fn install_components_from_repo( } /// Lee un `.swm` (YAML) de disco a `Swm`. Equivalente al helper homónimo de la CLI (privado allí). -fn load_swm_file(path: &Path) -> Result { +fn load_swm_file(path: &Path) -> Result { let yaml = std::fs::read_to_string(path) .map_err(|e| Error::Other(format!("no pude leer {}: {e}", path.display())))?; - hammer_core::Swm::from_yaml(&yaml) + takana_core::Swm::from_yaml(&yaml) .map_err(|e| Error::Other(format!("no pude parsear {}: {e}", path.display()))) } /// Primera mutación `SourcePatch` de un `.swm` (un paquete hammer es un único source_patch). -fn source_patch_of(swm: &hammer_core::Swm) -> Option<&hammer_core::Mutation> { +fn source_patch_of(swm: &takana_core::Swm) -> Option<&takana_core::Mutation> { swm.mutations .iter() - .find(|m| matches!(m, hammer_core::Mutation::SourcePatch { .. })) + .find(|m| matches!(m, takana_core::Mutation::SourcePatch { .. })) } // ── Producto ATESTADO: la capa FIRMADA que el gate de arje verifica al boot (I4 / Etapa D) ─────── @@ -966,7 +966,7 @@ fn assemble_attested_product_rootfs( base_dir.display() ))); } - hammer_build::run_hydrate(&base_dir, staging, hammer_core::LinkMode::Static, None)?; + takana_build::run_hydrate(&base_dir, staging, takana_core::LinkMode::Static, None)?; let _ = std::fs::remove_dir_all(staging.join(".hammer")); // 2) PISAR /usr/bin/arje-zero con el init CON gate. Es un hardlink read-only al store ⇒ romper el @@ -1071,7 +1071,7 @@ fn assemble_attested_product_rootfs( /// base quedan intactos (Separación Mecanismo/Política): el atestado es un sello APARTE. pub fn product_attested( base: &RootfsHash, - base_cfg: &hammer_build::BuildConfig, + base_cfg: &takana_build::BuildConfig, recipes_dir: &Path, store: &Store, cfg: &AttestConfig, @@ -1245,7 +1245,7 @@ pub struct AllReport { pub fn all( seed: &SeedSpec, recipes_dir: &Path, - base_cfg: &hammer_build::BuildConfig, + base_cfg: &takana_build::BuildConfig, store: &Store, ) -> Result { let seed_hash = stage0(seed, store)?; @@ -1505,7 +1505,7 @@ fn assemble_builder(spec: &BuilderSpec, store: &Store, staging: &Path) -> Result stage1_dir.display() ))); } - hammer_build::run_hydrate(&stage1_dir, staging, hammer_core::LinkMode::Static, None)?; + takana_build::run_hydrate(&stage1_dir, staging, takana_core::LinkMode::Static, None)?; // 2) Esqueleto del builder: el sandbox de build (/toolchain), el store, el work y la config. for d in ["toolchain", "store", "work", "usr/bin", "etc/hammer/recipes"] { @@ -1953,7 +1953,7 @@ mod tests { fn seed_build_config_points_zig_dir_at_seed() { let tmp = tempfile::tempdir().unwrap(); let (store, seed) = seal_seed_with_zig_at(tmp.path(), "zig-linux-x86_64-0.13.0/zig"); - let base = hammer_build::BuildConfig::defaults_for_store(store.root()); + let base = takana_build::BuildConfig::defaults_for_store(store.root()); let cfg = seed_build_config(&base, &seed, &store).unwrap(); assert_eq!(cfg.zig_dir, seed.toolchain_dir(&store).unwrap()); // El resto de la config se hereda sin cambios. @@ -2360,7 +2360,7 @@ open(os.path.join(os.path.dirname(out),"..","..","bins-seen.txt"),"w").write("\n let path = recipes_dir.join(format!("{name}.toml")); let r = Recipe::load_from_path(&path).unwrap_or_else(|e| panic!("parse {name}: {e}")); assert_eq!(&r.name, name); - let h = hammer_build::artifact_hash(&r, &store, &hammer_core::lab::LabFingerprint::for_tests()).expect("hash"); + let h = takana_build::artifact_hash(&r, &store, &takana_core::lab::LabFingerprint::for_tests()).expect("hash"); assert!(h.as_str().starts_with("b3:")); } } @@ -2375,7 +2375,7 @@ open(os.path.join(os.path.dirname(out),"..","..","bins-seen.txt"),"w").write("\n let path = recipes_dir.join(format!("{name}.toml")); let r = Recipe::load_from_path(&path).unwrap_or_else(|e| panic!("parse {name}: {e}")); assert_eq!(&r.name, name); - let h = hammer_build::artifact_hash(&r, &store, &hammer_core::lab::LabFingerprint::for_tests()).expect("hash"); + let h = takana_build::artifact_hash(&r, &store, &takana_core::lab::LabFingerprint::for_tests()).expect("hash"); assert!(h.as_str().starts_with("b3:"), "hash con prefijo b3:"); } } @@ -2696,7 +2696,7 @@ open(os.path.join(os.path.dirname(out),"..","..","bins-seen.txt"),"w").write("\n } let r = Recipe::load_from_path(&path) .unwrap_or_else(|e| panic!("parse {}: {e}", path.display())); - let h = hammer_build::artifact_hash(&r, &store, &hammer_core::lab::LabFingerprint::for_tests()) + let h = takana_build::artifact_hash(&r, &store, &takana_core::lab::LabFingerprint::for_tests()) .unwrap_or_else(|e| panic!("hash {}: {e}", path.display())); assert!(h.as_str().starts_with("b3:"), "{}: hash con prefijo b3:", path.display()); count += 1; diff --git a/crates/hammer-bootstrap/src/manifest.rs b/crates/takana-bootstrap/src/manifest.rs similarity index 99% rename from crates/hammer-bootstrap/src/manifest.rs rename to crates/takana-bootstrap/src/manifest.rs index 8062421d..54be7eba 100644 --- a/crates/hammer-bootstrap/src/manifest.rs +++ b/crates/takana-bootstrap/src/manifest.rs @@ -10,7 +10,7 @@ use std::path::PathBuf; -use hammer_core::{ArtifactHash, Store}; +use takana_core::{ArtifactHash, Store}; use serde::{Deserialize, Serialize}; use crate::{Error, Result}; diff --git a/crates/hammer-build/Cargo.toml b/crates/takana-build/Cargo.toml similarity index 93% rename from crates/hammer-build/Cargo.toml rename to crates/takana-build/Cargo.toml index 34e66be0..5c252934 100644 --- a/crates/hammer-build/Cargo.toml +++ b/crates/takana-build/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-build" +name = "takana-build" version.workspace = true edition.workspace = true license.workspace = true @@ -8,7 +8,7 @@ repository.workspace = true description = "El laboratorio de hammer: sandbox de build (bubblewrap + zig cc) e hidratación." [dependencies] -hammer-core.workspace = true +takana-core.workspace = true anyhow.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/hammer-build/src/config.rs b/crates/takana-build/src/config.rs similarity index 100% rename from crates/hammer-build/src/config.rs rename to crates/takana-build/src/config.rs diff --git a/crates/hammer-build/src/download.rs b/crates/takana-build/src/download.rs similarity index 89% rename from crates/hammer-build/src/download.rs rename to crates/takana-build/src/download.rs index 58e7f8c8..5ca622ec 100644 --- a/crates/hammer-build/src/download.rs +++ b/crates/takana-build/src/download.rs @@ -12,7 +12,7 @@ use std::process::Command; /// Descarga `url` y devuelve su contenido en memoria. Falla con el stderr de curl si el /// código de salida no es 0 (incluye errores HTTP gracias a `-f`). -pub fn fetch_url_bytes(url: &str) -> hammer_core::Result> { +pub fn fetch_url_bytes(url: &str) -> takana_core::Result> { let out = Command::new("curl") .args([ "-fsSL", @@ -25,9 +25,9 @@ pub fn fetch_url_bytes(url: &str) -> hammer_core::Result> { url, ]) .output() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn curl: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn curl: {e}")))?; if !out.status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "curl {url} falló (exit {}): {}", out.status.code().map(|c| c.to_string()).unwrap_or_else(|| "?".into()), String::from_utf8_lossy(&out.stderr).trim() @@ -37,7 +37,7 @@ pub fn fetch_url_bytes(url: &str) -> hammer_core::Result> { } /// Descarga `url` y lo escribe en `dst` (creando los directorios padre). -pub fn fetch_url_to_file(url: &str, dst: &Path) -> hammer_core::Result<()> { +pub fn fetch_url_to_file(url: &str, dst: &Path) -> takana_core::Result<()> { let bytes = fetch_url_bytes(url)?; if let Some(parent) = dst.parent() { std::fs::create_dir_all(parent)?; @@ -49,14 +49,14 @@ pub fn fetch_url_to_file(url: &str, dst: &Path) -> hammer_core::Result<()> { /// Verifica que el sha256 de `path` coincide con `expected` (hex, case-insensitive). Lo usan /// los consumidores que ingieren una fuente fijada (p. ej. el toolchain semilla del bootstrap, /// [SDD 11](../../docs/11-bootstrap.md)) y necesitan comprobar integridad **antes** de sellar. -pub fn verify_sha256(path: &Path, expected: &str) -> hammer_core::Result<()> { +pub fn verify_sha256(path: &Path, expected: &str) -> takana_core::Result<()> { use sha2::{Digest, Sha256}; let mut f = std::fs::File::open(path)?; let mut hasher = Sha256::new(); std::io::copy(&mut f, &mut hasher)?; let got = hex::encode(hasher.finalize()); if !got.eq_ignore_ascii_case(expected) { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "sha256 mismatch en {}: esperado {expected}, obtenido {got}", path.display() ))); diff --git a/crates/hammer-build/src/fetch.rs b/crates/takana-build/src/fetch.rs similarity index 93% rename from crates/hammer-build/src/fetch.rs rename to crates/takana-build/src/fetch.rs index c93c26f9..167dada0 100644 --- a/crates/hammer-build/src/fetch.rs +++ b/crates/takana-build/src/fetch.rs @@ -1,6 +1,6 @@ //! Fase `fetch`: materializa el árbol fuente de la receta en un directorio trabajable. //! -//! Dos modos, decididos por la receta (ver `hammer_core::SourceKind`): +//! Dos modos, decididos por la receta (ver `takana_core::SourceKind`): //! //! * **Git** — mirror local en `/repos/.git` + `git archive` del commit //! fijado al árbol trabajable. El mirror se reusa entre builds; el árbol es descartable. @@ -14,10 +14,10 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; -use hammer_core::{Recipe, SourceKind}; +use takana_core::{Recipe, SourceKind}; /// Materializa el árbol fuente en un directorio trabajable y devuelve su ruta. -pub fn fetch(recipe: &Recipe, work_root: &Path) -> hammer_core::Result { +pub fn fetch(recipe: &Recipe, work_root: &Path) -> takana_core::Result { match recipe.source.kind()? { SourceKind::Git { repo, commit } => fetch_git(recipe, repo, commit, work_root), SourceKind::Tarball { url, sha256 } => fetch_tarball(recipe, url, sha256, work_root), @@ -34,16 +34,16 @@ pub fn fetch(recipe: &Recipe, work_root: &Path) -> hammer_core::Result /// /// El nombre del workspace lleva el hash del CONTENIDO y no el de la ruta: editar el overlay cambia /// de directorio, así que un árbol viejo nunca se reusa por accidente. -fn fetch_dir(recipe: &Recipe, dir: &str, work_root: &Path) -> hammer_core::Result { +fn fetch_dir(recipe: &Recipe, dir: &str, work_root: &Path) -> takana_core::Result { let origen = recipe.base_dir.join(dir); if !origen.is_dir() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "source.dir apunta a {} y no es un directorio", origen.display() ))); } - let h = hammer_core::ArtifactHash::of_tree(&origen) - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("hash del árbol {}: {e}", origen.display())))?; + let h = takana_core::ArtifactHash::of_tree(&origen) + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("hash del árbol {}: {e}", origen.display())))?; let bare = h.as_str().strip_prefix("b3:").unwrap_or(h.as_str()); let sources_dir = work_root.join("sources"); std::fs::create_dir_all(&sources_dir)?; @@ -57,9 +57,9 @@ fn fetch_dir(recipe: &Recipe, dir: &str, work_root: &Path) -> hammer_core::Resul .arg(format!("{}/.", origen.display())) .arg(&work_tree) .status() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn cp -a del source.dir: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn cp -a del source.dir: {e}")))?; if !st.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "cp -a de {} falló", origen.display() ))); @@ -72,7 +72,7 @@ fn fetch_git( repo: &str, commit: &str, work_root: &Path, -) -> hammer_core::Result { +) -> takana_core::Result { let repos_dir = work_root.join("repos"); let sources_dir = work_root.join("sources"); std::fs::create_dir_all(&repos_dir)?; @@ -105,7 +105,7 @@ fn fetch_git( if run_git(&["cat-file", "-e", commit], Some(&mirror)).is_err() { run_git(&["fetch", "--all", "--tags"], Some(&mirror))?; run_git(&["cat-file", "-e", commit], Some(&mirror)).map_err(|_| { - hammer_core::Error::Other(anyhow::anyhow!( + takana_core::Error::Other(anyhow::anyhow!( "commit {commit} no existe en {repo} tras fetch" )) })?; @@ -131,7 +131,7 @@ fn fetch_git( } /// `git archive | tar -x -C `: materializa UN árbol sin pagar un worktree. -fn archivar_en(mirror: &Path, commit: &str, destino: &Path) -> hammer_core::Result<()> { +fn archivar_en(mirror: &Path, commit: &str, destino: &Path) -> takana_core::Result<()> { let archive = Command::new("git") .arg("-C") .arg(mirror) @@ -139,7 +139,7 @@ fn archivar_en(mirror: &Path, commit: &str, destino: &Path) -> hammer_core::Resu .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn git archive: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn git archive: {e}")))?; let tar_status = Command::new("tar") .args(["-x", "-C"]) @@ -148,10 +148,10 @@ fn archivar_en(mirror: &Path, commit: &str, destino: &Path) -> hammer_core::Resu .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .status() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn tar -x: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn tar -x: {e}")))?; if !tar_status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "git archive | tar -x falló (tar exit {:?})", tar_status.code() ))); @@ -184,13 +184,13 @@ fn materializar_submodulos( repos_dir: &Path, url_padre: &str, profundidad: usize, -) -> hammer_core::Result<()> { +) -> takana_core::Result<()> { let gitlinks = gitlinks_de(mirror, commit)?; if gitlinks.is_empty() { return Ok(()); } if profundidad >= PROFUNDIDAD_SUBMODULOS { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "submódulos anidados más de {PROFUNDIDAD_SUBMODULOS} niveles en {url_padre} \ ({commit}): parece un ciclo" ))); @@ -200,7 +200,7 @@ fn materializar_submodulos( for (sha, ruta) in gitlinks { let declarada = urls.get(&ruta).ok_or_else(|| { - hammer_core::Error::Other(anyhow::anyhow!( + takana_core::Error::Other(anyhow::anyhow!( "el commit {commit} declara el submódulo `{ruta}` pero .gitmodules no le da url" )) })?; @@ -222,7 +222,7 @@ fn materializar_submodulos( if run_git(&["cat-file", "-e", &sha], Some(&sub_mirror)).is_err() { run_git(&["fetch", "--all", "--tags"], Some(&sub_mirror))?; run_git(&["cat-file", "-e", &sha], Some(&sub_mirror)).map_err(|_| { - hammer_core::Error::Other(anyhow::anyhow!( + takana_core::Error::Other(anyhow::anyhow!( "el submódulo `{ruta}` pide {sha}, que no existe en {url} tras fetch" )) })?; @@ -246,7 +246,7 @@ fn materializar_submodulos( /// Las entradas de tipo `commit` (modo 160000) del commit: `(sha, ruta)`. /// /// `-z` porque una ruta puede llevar espacios y el formato sin `-z` los escapa con comillas. -fn gitlinks_de(mirror: &Path, commit: &str) -> hammer_core::Result> { +fn gitlinks_de(mirror: &Path, commit: &str) -> takana_core::Result> { let salida = salida_git(&["ls-tree", "-r", "-z", commit], mirror)?; let mut out = Vec::new(); for reg in salida.split('\0').filter(|r| !r.is_empty()) { @@ -269,7 +269,7 @@ fn gitlinks_de(mirror: &Path, commit: &str) -> hammer_core::Result hammer_core::Result> { +) -> takana_core::Result> { let blob = format!("{commit}:.gitmodules"); let salida = match salida_git( &[ @@ -365,7 +365,7 @@ fn sanear_para_ruta(url: &str) -> String { } /// `git ` capturando stdout. Error si el comando falla. -fn salida_git(args: &[&str], cwd: &Path) -> hammer_core::Result { +fn salida_git(args: &[&str], cwd: &Path) -> takana_core::Result { let out = Command::new("git") .arg("-C") .arg(cwd) @@ -373,9 +373,9 @@ fn salida_git(args: &[&str], cwd: &Path) -> hammer_core::Result { .stdin(Stdio::null()) .stderr(Stdio::piped()) .output() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn git {args:?}: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn git {args:?}: {e}")))?; if !out.status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "git {args:?} falló (exit {:?})", out.status.code() ))); @@ -544,7 +544,7 @@ fn fetch_tarball( url: &str, sha256: &str, work_root: &Path, -) -> hammer_core::Result { +) -> takana_core::Result { let tarballs_dir = work_root.join("tarballs"); let sources_dir = work_root.join("sources"); std::fs::create_dir_all(&tarballs_dir)?; @@ -595,9 +595,9 @@ fn fetch_tarball( .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .status() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn tar -x tarball: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn tar -x tarball: {e}")))?; if !status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "tar -x falló (exit {:?})", status.code() ))); @@ -628,7 +628,7 @@ fn fetch_tarball( /// `{base}/{sha256}.tar` en cada uno, en el orden que dicta [`bases_de_mirror`]. /// `HAMMER_MIRROR_KEY`, si está, se pasa como `--key` (Storage Box por sftp). Sin `HAMMER_MIRROR` /// el comportamiento es el de siempre: derecho a upstream. -fn fetch_con_mirror(url: &str, sha256: &str, dst: &Path) -> hammer_core::Result<()> { +fn fetch_con_mirror(url: &str, sha256: &str, dst: &Path) -> takana_core::Result<()> { for base in bases_de_mirror("HAMMER_MIRROR", sha256) { let espejo = format!("{base}/{sha256}.tar"); // Un fallo acá NO es un error: es el caso normal la primera vez que se ve una fuente, y @@ -645,7 +645,7 @@ fn fetch_con_mirror(url: &str, sha256: &str, dst: &Path) -> hammer_core::Result< /// para que la próxima corrida lo vuelva a intentar (no envenenamos la caché). /// Baja `url` a `dst` con curl. Sin verificar nada: quien llama decide cómo se comprueba — /// `download_verify` por sha256 (tarballs), `hidratar_desde_bundle` delegando en git (bundles). -fn descargar(url: &str, dst: &Path) -> hammer_core::Result<()> { +fn descargar(url: &str, dst: &Path) -> takana_core::Result<()> { let mut cmd = Command::new("curl"); cmd.args(["-fL", "--retry", "3", "--connect-timeout", "30"]); // Clave para el mirror por sftp (Storage Box). Inocua para http/file. @@ -661,9 +661,9 @@ fn descargar(url: &str, dst: &Path) -> hammer_core::Result<()> { .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .status() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn curl: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn curl: {e}")))?; if !status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "curl {url} falló (exit {:?})", status.code() ))); @@ -671,7 +671,7 @@ fn descargar(url: &str, dst: &Path) -> hammer_core::Result<()> { Ok(()) } -fn download_verify(url: &str, sha256: &str, dst: &Path) -> hammer_core::Result<()> { +fn download_verify(url: &str, sha256: &str, dst: &Path) -> takana_core::Result<()> { let tmp = dst.with_extension("tar.partial"); if let Err(e) = descargar(url, &tmp) { let _ = std::fs::remove_file(&tmp); @@ -685,14 +685,14 @@ fn download_verify(url: &str, sha256: &str, dst: &Path) -> hammer_core::Result<( Ok(()) } -fn verify_sha256(path: &Path, expected: &str) -> hammer_core::Result<()> { +fn verify_sha256(path: &Path, expected: &str) -> takana_core::Result<()> { use sha2::{Digest, Sha256}; let mut f = std::fs::File::open(path)?; let mut hasher = Sha256::new(); std::io::copy(&mut f, &mut hasher)?; let got = hex::encode(hasher.finalize()); if !got.eq_ignore_ascii_case(expected) { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "sha256 mismatch en {}: esperado {expected}, obtenido {got}", path.display() ))); @@ -714,7 +714,7 @@ fn verify_sha256(path: &Path, expected: &str) -> hammer_core::Result<()> { /// (plan C.2 #5). Ver `docs/runbooks/stage1-vm-boot.md` §8. /// /// Un crate sin deps de crates.io produce un config vacío y ningún `vendor/`: inocuo. -pub fn vendor_cargo_deps(src: &Path, vendor_dir: &str) -> hammer_core::Result<()> { +pub fn vendor_cargo_deps(src: &Path, vendor_dir: &str) -> takana_core::Result<()> { let locked = src.join("Cargo.lock").is_file(); let mut args: Vec<&str> = vec!["vendor"]; if locked { @@ -735,9 +735,9 @@ pub fn vendor_cargo_deps(src: &Path, vendor_dir: &str) -> hammer_core::Result<() .args(&args) .stderr(Stdio::inherit()) .output() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn cargo vendor: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn cargo vendor: {e}")))?; if !output.status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "cargo vendor falló (exit {:?})", output.status.code() ))); @@ -762,7 +762,7 @@ pub fn vendor_cargo_deps(src: &Path, vendor_dir: &str) -> hammer_core::Result<() /// `GOFLAGS=-mod=mod` permite poblar el `vendor/` aunque el árbol no lo traiga. /// /// Un proyecto sin deps externas produce un `vendor/` vacío (o ninguno): inocuo. -pub fn vendor_go_deps(src: &Path) -> hammer_core::Result<()> { +pub fn vendor_go_deps(src: &Path) -> takana_core::Result<()> { // Proyecto WORKSPACE (multimódulo): si el árbol trae `go.work`, `go mod vendor` con GOWORK=off // vendorea SÓLO el módulo raíz → el build (que ve todo el workspace) se queja de "inconsistent // vendoring". `go work vendor` (go 1.22+) produce un `vendor/` consistente para TODO el workspace. @@ -787,13 +787,13 @@ pub fn vendor_go_deps(src: &Path) -> hammer_core::Result<()> { .stderr(Stdio::inherit()) .output() .map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!( + takana_core::Error::Other(anyhow::anyhow!( "spawn {label}: {e} (¿está `go` en el PATH del host? lo provee el lab, \ cf. scripts/bootstrap-devfs.sh / vps-setup.sh)" )) })?; if !output.status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "{label} falló (exit {:?})", output.status.code() ))); @@ -802,11 +802,11 @@ pub fn vendor_go_deps(src: &Path) -> hammer_core::Result<()> { } /// Aplica los patches de la receta (relativos a `recipe.base_dir`) sobre `tree`. -pub fn apply_patches(recipe: &Recipe, tree: &Path) -> hammer_core::Result<()> { +pub fn apply_patches(recipe: &Recipe, tree: &Path) -> takana_core::Result<()> { for p in &recipe.source.patches { let patch_path = recipe.base_dir.join(p); let bytes = std::fs::read(&patch_path).map_err(|e| { - hammer_core::Error::Recipe(format!( + takana_core::Error::Recipe(format!( "no pude leer patch {}: {e}", patch_path.display() )) @@ -818,18 +818,18 @@ pub fn apply_patches(recipe: &Recipe, tree: &Path) -> hammer_core::Result<()> { .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .spawn() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn patch: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn patch: {e}")))?; if let Some(mut stdin) = child.stdin.take() { use std::io::Write; stdin .write_all(&bytes) - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("write patch: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("write patch: {e}")))?; } let status = child .wait() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("wait patch: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("wait patch: {e}")))?; if !status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "patch {} falló (exit {:?})", patch_path.display(), status.code() @@ -1047,7 +1047,7 @@ mod tests { } } -fn run_git(args: &[&str], cwd: Option<&Path>) -> hammer_core::Result<()> { +fn run_git(args: &[&str], cwd: Option<&Path>) -> takana_core::Result<()> { let mut cmd = Command::new("git"); if let Some(c) = cwd { cmd.arg("-C").arg(c); @@ -1058,9 +1058,9 @@ fn run_git(args: &[&str], cwd: Option<&Path>) -> hammer_core::Result<()> { .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .status() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn git {args:?}: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn git {args:?}: {e}")))?; if !status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "git {args:?} falló (exit {:?})", status.code() ))); diff --git a/crates/hammer-build/src/harkaq.rs b/crates/takana-build/src/harkaq.rs similarity index 96% rename from crates/hammer-build/src/harkaq.rs rename to crates/takana-build/src/harkaq.rs index 0f344853..638d3496 100644 --- a/crates/hammer-build/src/harkaq.rs +++ b/crates/takana-build/src/harkaq.rs @@ -70,19 +70,19 @@ impl Harkaq { deps: &[PathBuf], contratos: &[String], dst: &Path, - ) -> hammer_core::Result<()> { + ) -> takana_core::Result<()> { let mut ro: Vec = Vec::new(); let mut dirs: std::collections::BTreeSet = Default::default(); for dep in deps { let real = std::fs::canonicalize(dep).map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!("canonicalize {}: {e}", dep.display())) + takana_core::Error::Other(anyhow::anyhow!("canonicalize {}: {e}", dep.display())) })?; recorrer(&real, &real, &mut ro, &mut dirs)?; } let mut f = std::fs::File::create(dst).map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!("crear política {}: {e}", dst.display())) + takana_core::Error::Other(anyhow::anyhow!("crear política {}: {e}", dst.display())) })?; writeln!(f, "# harkaq: clausura derivada de {} dep(s)", deps.len()).ok(); @@ -98,7 +98,7 @@ impl Harkaq { if let Some(base) = &self.base { let txt = std::fs::read_to_string(base).map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!("leer HARKAQ_BASE {}: {e}", base.display())) + takana_core::Error::Other(anyhow::anyhow!("leer HARKAQ_BASE {}: {e}", base.display())) })?; writeln!(f, "# runtime base ({})", base.display()).ok(); f.write_all(txt.as_bytes()).ok(); @@ -130,7 +130,7 @@ impl Harkaq { deps: &[PathBuf], contratos: &[String], id: &str, - ) -> hammer_core::Result { + ) -> takana_core::Result { let tmp = std::env::temp_dir().join(format!("harkaq-{id}-{}", std::process::id())); std::fs::create_dir_all(&tmp).ok(); let policy = tmp.join("policy"); @@ -146,7 +146,7 @@ impl Harkaq { let verdict = tmp.join("verdict.json"); let vf = std::fs::File::create(&verdict).map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!("crear verdict: {e}")) + takana_core::Error::Other(anyhow::anyhow!("crear verdict: {e}")) })?; let reader = Command::new(self.bin.join("harkaq-audit")) .arg("--canary") @@ -157,7 +157,7 @@ impl Harkaq { .stderr(Stdio::inherit()) .spawn() .map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!( + takana_core::Error::Other(anyhow::anyhow!( "spawn harkaq-audit ({}): {e} — ¿compilado y con `setcap cap_audit_read`?", self.bin.display() )) @@ -199,7 +199,7 @@ fn recorrer( dir: &Path, ro: &mut Vec, dirs: &mut std::collections::BTreeSet, -) -> hammer_core::Result<()> { +) -> takana_core::Result<()> { let rd = match std::fs::read_dir(dir) { Ok(r) => r, Err(_) => return Ok(()), diff --git a/crates/hammer-build/src/hydrate.rs b/crates/takana-build/src/hydrate.rs similarity index 93% rename from crates/hammer-build/src/hydrate.rs rename to crates/takana-build/src/hydrate.rs index 903ddb9a..21785b4a 100644 --- a/crates/hammer-build/src/hydrate.rs +++ b/crates/takana-build/src/hydrate.rs @@ -15,7 +15,7 @@ use std::os::unix::fs::FileTypeExt; use std::path::{Path, PathBuf}; use std::process::Command; -use hammer_core::LinkMode; +use takana_core::LinkMode; #[derive(Debug, Clone)] pub struct HydratedFile { @@ -61,7 +61,7 @@ pub fn hydrate( target_fhs: &Path, mode: LinkMode, dynamic: Option<&DynamicSpec>, -) -> hammer_core::Result { +) -> takana_core::Result { // `is_dir()` a secas acepta un directorio VACÍO: hydrate proyectaría 0 ficheros y devolvería // un HydrateReport de éxito. Es el mismo agujero que ya se tapó en `Store::has` (2026-08-10) y // en `Store::seal` (2026-08-29): un vacío no es un artefacto, es un nombre. Acá duele especial @@ -71,7 +71,7 @@ pub fn hydrate( .map(|mut e| e.next().is_none()) .unwrap_or(true); if !artifact_dir.is_dir() || vacio { - return Err(hammer_core::Error::Store(format!( + return Err(takana_core::Error::Store(format!( "artefacto inexistente o VACÍO: {}", artifact_dir.display() ))); @@ -93,7 +93,7 @@ pub fn hydrate( // La raíz REAL contra la que se mide la contención (ver `no_escapa`). Se resuelve una sola vez: // si el propio `target_fhs` es un symlink, eso es elección de quien hidrata y vale como raíz. let raiz = target_fhs.canonicalize().map_err(|e| { - hammer_core::Error::Store(format!("canonicalize {}: {e}", target_fhs.display())) + takana_core::Error::Store(format!("canonicalize {}: {e}", target_fhs.display())) })?; let mut report = HydrateReport::default(); @@ -121,12 +121,12 @@ pub fn hydrate( /// entre las dos. Para el fallo real —un symlink persistente puesto por otro artefacto— alcanza y /// es determinista; la versión sin carrera es mover las escrituras a `openat2` + `linkat`/`renameat` /// (SDD 25 §7-H3), y eso arrastra el camino de `patchelf`. -fn no_escapa(raiz: &Path, dst: &Path) -> hammer_core::Result<()> { +fn no_escapa(raiz: &Path, dst: &Path) -> takana_core::Result<()> { let real = dst.canonicalize().map_err(|e| { - hammer_core::Error::Store(format!("canonicalize {}: {e}", dst.display())) + takana_core::Error::Store(format!("canonicalize {}: {e}", dst.display())) })?; if !real.starts_with(raiz) { - return Err(hammer_core::Error::Store(format!( + return Err(takana_core::Error::Store(format!( "la hidratación se saldría del root: {} lleva a {}, fuera de {}.\n\ Es un symlink de directorio ya presente en el FHS (probablemente puesto por otro \ artefacto). No se escribe a través de él: borralo o hidratá sobre un root limpio.", @@ -145,7 +145,7 @@ fn walk_and_link( raiz: &Path, spec: Option<&DynamicSpec>, report: &mut HydrateReport, -) -> hammer_core::Result<()> { +) -> takana_core::Result<()> { for entry in std::fs::read_dir(cur)? { let entry = entry?; let src = entry.path(); @@ -183,7 +183,7 @@ fn walk_and_link( report.files.push(HydratedFile { src, dst }); } else if ft.is_block_device() || ft.is_char_device() || ft.is_fifo() || ft.is_socket() { // Los artefactos del lab no deberían contener nodos especiales; lo señalamos. - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "tipo no soportado en {}: {ft:?}", src.display() ))); @@ -195,7 +195,7 @@ fn walk_and_link( /// Crea un hardlink `dst → src` reemplazando atómicamente cualquier archivo previo en `dst`. /// Implementación: `link(src, dst.tmp)` + `rename(dst.tmp, dst)`. La técnica garantiza que /// el archivo en `dst` nunca queda en estado intermedio y que el inode del store no se toca. -fn atomic_hardlink(src: &Path, dst: &Path) -> hammer_core::Result<()> { +fn atomic_hardlink(src: &Path, dst: &Path) -> takana_core::Result<()> { if let Some(parent) = dst.parent() { std::fs::create_dir_all(parent)?; } @@ -203,7 +203,7 @@ fn atomic_hardlink(src: &Path, dst: &Path) -> hammer_core::Result<()> { // Limpia un tmp olvidado de una corrida anterior. let _ = std::fs::remove_file(&tmp); std::fs::hard_link(src, &tmp).map_err(|e| { - hammer_core::Error::Store(format!( + takana_core::Error::Store(format!( "hardlink {} → {}: {e}", src.display(), tmp.display() @@ -212,7 +212,7 @@ fn atomic_hardlink(src: &Path, dst: &Path) -> hammer_core::Result<()> { // rename sobreescribe atómicamente si dst es un archivo (no si es directorio). if let Err(e) = std::fs::rename(&tmp, dst) { let _ = std::fs::remove_file(&tmp); - return Err(hammer_core::Error::Store(format!( + return Err(takana_core::Error::Store(format!( "rename {} → {}: {e}", tmp.display(), dst.display() @@ -223,7 +223,7 @@ fn atomic_hardlink(src: &Path, dst: &Path) -> hammer_core::Result<()> { /// `true` si el archivo empieza por el magic ELF (`\x7fELF`). Errores de I/O se propagan; /// un archivo más corto que 4 bytes simplemente no es ELF. -fn is_elf(path: &Path) -> hammer_core::Result { +fn is_elf(path: &Path) -> takana_core::Result { use std::io::Read; let mut f = std::fs::File::open(path)?; let mut magic = [0u8; 4]; @@ -235,14 +235,14 @@ fn is_elf(path: &Path) -> hammer_core::Result { } /// Verifica que `patchelf` esté disponible antes de empezar a proyectar. -fn ensure_patchelf() -> hammer_core::Result<()> { +fn ensure_patchelf() -> takana_core::Result<()> { match Command::new("patchelf").arg("--version").output() { Ok(o) if o.status.success() => Ok(()), - Ok(o) => Err(hammer_core::Error::Other(anyhow::anyhow!( + Ok(o) => Err(takana_core::Error::Other(anyhow::anyhow!( "patchelf falló al invocarse: {}", String::from_utf8_lossy(&o.stderr).trim() ))), - Err(e) => Err(hammer_core::Error::Other(anyhow::anyhow!( + Err(e) => Err(takana_core::Error::Other(anyhow::anyhow!( "hidratación dinámica requiere `patchelf` en el PATH y no se pudo ejecutar: {e}" ))), } @@ -251,14 +251,14 @@ fn ensure_patchelf() -> hammer_core::Result<()> { /// Copia `src → dst` atómicamente (copy a tmp → patchelf el tmp → rename), preservando los /// permisos (`std::fs::copy` los replica, incluido el bit de ejecución). Patcheamos el tmp /// **antes** del rename para que `dst` nunca quede en un estado a medio parchear. -fn atomic_copy_and_patch(src: &Path, dst: &Path, spec: &DynamicSpec) -> hammer_core::Result<()> { +fn atomic_copy_and_patch(src: &Path, dst: &Path, spec: &DynamicSpec) -> takana_core::Result<()> { if let Some(parent) = dst.parent() { std::fs::create_dir_all(parent)?; } let tmp = with_suffix(dst, ".hammer-tmp"); let _ = std::fs::remove_file(&tmp); std::fs::copy(src, &tmp).map_err(|e| { - hammer_core::Error::Store(format!("copy {} → {}: {e}", src.display(), tmp.display())) + takana_core::Error::Store(format!("copy {} → {}: {e}", src.display(), tmp.display())) })?; if let Err(e) = run_patchelf(&tmp, spec) { let _ = std::fs::remove_file(&tmp); @@ -266,7 +266,7 @@ fn atomic_copy_and_patch(src: &Path, dst: &Path, spec: &DynamicSpec) -> hammer_c } if let Err(e) = std::fs::rename(&tmp, dst) { let _ = std::fs::remove_file(&tmp); - return Err(hammer_core::Error::Store(format!( + return Err(takana_core::Error::Store(format!( "rename {} → {}: {e}", tmp.display(), dst.display() @@ -277,7 +277,7 @@ fn atomic_copy_and_patch(src: &Path, dst: &Path, spec: &DynamicSpec) -> hammer_c /// Ejecuta `patchelf [--set-interpreter I] [--set-rpath R] `. Asume que el caller ya /// comprobó (`has_work`) que hay al menos una de las dos. -fn run_patchelf(file: &Path, spec: &DynamicSpec) -> hammer_core::Result<()> { +fn run_patchelf(file: &Path, spec: &DynamicSpec) -> takana_core::Result<()> { let mut cmd = Command::new("patchelf"); if let Some(interp) = &spec.interpreter { cmd.arg("--set-interpreter").arg(interp); @@ -287,13 +287,13 @@ fn run_patchelf(file: &Path, spec: &DynamicSpec) -> hammer_core::Result<()> { } cmd.arg(file); let out = cmd.output().map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!( + takana_core::Error::Other(anyhow::anyhow!( "no pude ejecutar patchelf sobre {}: {e}", file.display() )) })?; if !out.status.success() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "patchelf falló sobre {}: {}", file.display(), String::from_utf8_lossy(&out.stderr).trim() @@ -302,7 +302,7 @@ fn run_patchelf(file: &Path, spec: &DynamicSpec) -> hammer_core::Result<()> { Ok(()) } -fn atomic_replace_symlink(link_target: &Path, dst: &Path) -> hammer_core::Result<()> { +fn atomic_replace_symlink(link_target: &Path, dst: &Path) -> takana_core::Result<()> { use std::os::unix::fs::symlink; if let Some(parent) = dst.parent() { std::fs::create_dir_all(parent)?; @@ -310,11 +310,11 @@ fn atomic_replace_symlink(link_target: &Path, dst: &Path) -> hammer_core::Result let tmp = with_suffix(dst, ".hammer-tmp"); let _ = std::fs::remove_file(&tmp); symlink(link_target, &tmp).map_err(|e| { - hammer_core::Error::Store(format!("symlink {} → {}: {e}", link_target.display(), tmp.display())) + takana_core::Error::Store(format!("symlink {} → {}: {e}", link_target.display(), tmp.display())) })?; if let Err(e) = std::fs::rename(&tmp, dst) { let _ = std::fs::remove_file(&tmp); - return Err(hammer_core::Error::Store(format!( + return Err(takana_core::Error::Store(format!( "rename {} → {}: {e}", tmp.display(), dst.display() diff --git a/crates/hammer-build/src/lib.rs b/crates/takana-build/src/lib.rs similarity index 97% rename from crates/hammer-build/src/lib.rs rename to crates/takana-build/src/lib.rs index 4ea562ae..dad124d6 100644 --- a/crates/hammer-build/src/lib.rs +++ b/crates/takana-build/src/lib.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; -use hammer_core::{ArtifactHash, Compiler, LinkMode, Phases, Recipe, Store}; +use takana_core::{ArtifactHash, Compiler, LinkMode, Phases, Recipe, Store}; pub mod config; pub mod download; @@ -33,8 +33,8 @@ pub use swm_bridge::build_source_patch; pub fn artifact_hash( recipe: &Recipe, _store: &Store, - lab: &hammer_core::lab::LabFingerprint, -) -> hammer_core::Result { + lab: &takana_core::lab::LabFingerprint, +) -> takana_core::Result { let mut stack: Vec = Vec::new(); // Memo por path canónico de receta: el grafo de build es un DAG-diamante (p.ej. TODO KF6/Qt // converge en qtbase/kcoreaddons, alcanzables por decenas de rutas). Sin memoizar, el walk @@ -50,11 +50,11 @@ fn artifact_hash_rec( recipe: &Recipe, stack: &mut Vec, memo: &mut HashMap, - lab: &hammer_core::lab::LabFingerprint, -) -> hammer_core::Result { + lab: &takana_core::lab::LabFingerprint, +) -> takana_core::Result { if stack.iter().any(|n| n == &recipe.name) { stack.push(recipe.name.clone()); - return Err(hammer_core::Error::Recipe(format!( + return Err(takana_core::Error::Recipe(format!( "ciclo de dependencias de build: {}", stack.join(" -> ") ))); @@ -92,13 +92,13 @@ fn resolve_build_dep_hashes( recipe: &Recipe, stack: &mut Vec, memo: &mut HashMap, - lab: &hammer_core::lab::LabFingerprint, -) -> hammer_core::Result> { + lab: &takana_core::lab::LabFingerprint, +) -> takana_core::Result> { if recipe.deps.build.is_empty() { return Ok(Vec::new()); } if recipe.base_dir.as_os_str().is_empty() { - return Err(hammer_core::Error::Recipe(format!( + return Err(takana_core::Error::Recipe(format!( "la receta '{}' declara deps de build {:?} pero no tiene base_dir; \ cárgala con Recipe::load_from_path para resolver el catálogo", recipe.name, recipe.deps.build @@ -116,7 +116,7 @@ fn resolve_build_dep_hashes( continue; } let dep_recipe = Recipe::load_from_path(&dep_path).map_err(|e| { - hammer_core::Error::Recipe(format!( + takana_core::Error::Recipe(format!( "no pude cargar la dep de build '{dep}' de '{}' ({}): {e}", recipe.name, dep_path.display() @@ -138,12 +138,12 @@ fn materialize_build_deps( recipe: &Recipe, cfg: &BuildConfig, store: &Store, -) -> hammer_core::Result> { +) -> takana_core::Result> { if recipe.deps.build.is_empty() { return Ok(Vec::new()); } if recipe.base_dir.as_os_str().is_empty() { - return Err(hammer_core::Error::Recipe(format!( + return Err(takana_core::Error::Recipe(format!( "la receta '{}' declara deps de build {:?} pero no tiene base_dir; \ cárgala con Recipe::load_from_path para resolver el catálogo", recipe.name, recipe.deps.build @@ -153,7 +153,7 @@ fn materialize_build_deps( for dep in &recipe.deps.build { let dep_path = resolve_dep_path(&recipe.base_dir, dep); let dep_recipe = Recipe::load_from_path(&dep_path).map_err(|e| { - hammer_core::Error::Recipe(format!( + takana_core::Error::Recipe(format!( "no pude cargar la dep de build '{dep}' de '{}' ({}): {e}", recipe.name, dep_path.display() @@ -169,14 +169,14 @@ fn materialize_build_deps( /// la receta fije `build.zig_version`, en cuyo caso se usa el zig de esa versión, ubicado como /// **hermano** del por defecto (`<…>/zig-x86_64-linux-`, el layout de `.dev-fs/tools/`). /// Escotilla por-receta para esquivar la regresión de zig 0.14 sin tocar el toolchain global. -fn effective_zig_dir(cfg: &BuildConfig, recipe: &Recipe) -> hammer_core::Result { +fn effective_zig_dir(cfg: &BuildConfig, recipe: &Recipe) -> takana_core::Result { let Some(version) = &recipe.build.zig_version else { return Ok(cfg.zig_dir.clone()); }; let parent = cfg.zig_dir.parent().unwrap_or_else(|| Path::new(".")); let dir = parent.join(format!("zig-x86_64-linux-{version}")); if !dir.join("zig").is_file() { - return Err(hammer_core::Error::Recipe(format!( + return Err(takana_core::Error::Recipe(format!( "zig_version=\"{version}\": no encuentro el ejecutable zig en {} \ (bajá ese zig a {}/)", dir.display(), @@ -192,13 +192,13 @@ pub fn build( recipe: &Recipe, cfg: &BuildConfig, store: &Store, -) -> hammer_core::Result { +) -> takana_core::Result { // La huella sale del rootfs de ESTE cfg, que es el lab que de verdad va a compilar — no de // `docs/state/lab-toolchain.lock` ni de una ruta derivada del store. Derivarla del padre del // store ya mordió una vez (ver `BuildConfig::defaults_for_store_with_lab`): al anclar el store // de un worker a un volumen, el lab se buscaba donde no estaba. `cfg.rootfs` respeta // `HAMMER_LAB`/`HAMMER_ROOTFS` y es la única fuente que no puede desincronizarse del build. - let lab = hammer_core::lab::LabFingerprint::from_rootfs(&cfg.rootfs)?; + let lab = takana_core::lab::LabFingerprint::from_rootfs(&cfg.rootfs)?; let h = artifact_hash(recipe, store, &lab)?; if store.has(&h, &recipe.name) { tracing::info!(hash = %h, name = %recipe.name, "caché: artefacto ya en el store"); @@ -342,7 +342,7 @@ pub fn build( tracing::info!(cmd, "phase: compile"); sb.run(cmd)?; } else { - return Err(hammer_core::Error::Recipe( + return Err(takana_core::Error::Recipe( "receta sin fase 'compile' y heurística no encontró ninguna".into(), )); } @@ -350,7 +350,7 @@ pub fn build( tracing::info!(cmd, "phase: install"); sb.run(cmd)?; } else { - return Err(hammer_core::Error::Recipe( + return Err(takana_core::Error::Recipe( "receta sin fase 'install' y heurística no encontró ninguna".into(), )); } @@ -404,7 +404,7 @@ pub fn build( // seal, para que quede congelada en el árbol read-only del store. `hammer export` la // lee de vuelta para emitir `source_patch` con la receta original en vez de un // `file_drop` opaco. Ver `docs/04-overlay.md` §provenance (Fase 4). - let sidecar_path = out_dir.join(hammer_core::store::RECIPE_SIDECAR_REL); + let sidecar_path = out_dir.join(takana_core::store::RECIPE_SIDECAR_REL); if let Some(parent) = sidecar_path.parent() { std::fs::create_dir_all(parent)?; } @@ -419,9 +419,9 @@ pub fn build( /// El resultado de correr un check de evidencia, con su veredicto (H1b). #[derive(Debug, Clone)] pub struct EvidenceOutcome { - pub kind: hammer_core::EvidenceKind, + pub kind: takana_core::EvidenceKind, pub cmd: String, - pub outcome: hammer_core::CheckOutcome, + pub outcome: takana_core::CheckOutcome, } /// Reporte de la ejecución de TODA la evidencia de una receta (H1b). `all_passed` es el gate: @@ -437,7 +437,7 @@ impl EvidenceReport { } /// El estrato de confianza MÁS ALTO que pasó (para reportar "verificado hasta "). `None` /// si no hay checks. No promete que ese nivel *baste* — sólo que lo declarado a ese nivel pasó. - pub fn max_level_passed(&self) -> Option { + pub fn max_level_passed(&self) -> Option { self.results .iter() .filter(|r| r.outcome.passed) @@ -460,7 +460,7 @@ pub fn run_evidence( recipe: &Recipe, cfg: &BuildConfig, store: &Store, -) -> hammer_core::Result { +) -> takana_core::Result { recipe.evidence.validate()?; if recipe.evidence.checks.is_empty() { return Ok(EvidenceReport { results: Vec::new() }); @@ -615,7 +615,7 @@ fn inject_cargo_package_selector(recipe: &mut Recipe, src: &Path) { /// NO la considere parte del workspace del repo hammer (que la contiene en `work/sources/`). Append /// idempotente: si ya hay `[workspace]` (crate suelto que es su propio workspace, o una receta que /// lo parchea), no toca nada. Caso virtual-manifest (root ya es `[workspace]`) tampoco se toca. -fn ensure_cargo_workspace_isolation(src: &Path) -> hammer_core::Result<()> { +fn ensure_cargo_workspace_isolation(src: &Path) -> takana_core::Result<()> { let manifest = src.join("Cargo.toml"); let text = std::fs::read_to_string(&manifest)?; // Heurística simple: ¿hay una tabla `[workspace]` (al inicio de línea)? Cubre `[workspace]` y @@ -804,7 +804,7 @@ fn cargo_linker_env_var(triple: &str) -> String { /// Devuelve los comandos a ejecutar para cada fase: overrides explícitos en la receta /// ganan; el resto lo deriva la heurística según el sistema de build detectado. -fn resolve_phases(recipe: &Recipe, src: &Path) -> hammer_core::Result { +fn resolve_phases(recipe: &Recipe, src: &Path) -> takana_core::Result { let mut out = recipe.build.phases.clone(); // Raíz efectiva del módulo Go: `/` si la receta lo fija (dolt→go, csvtk→subdir), // si no `src`. detect/detect_go_main operan ahí; el compile hace `cd ` primero. @@ -1303,7 +1303,7 @@ commit = "deadbeef" let d = tempfile::tempdir().unwrap(); touch(d.path(), "Cargo.toml"); let mut r = recipe(&[]); - r.build.link = hammer_core::LinkMode::Dynamic; + r.build.link = takana_core::LinkMode::Dynamic; let c = resolve_phases(&r, d.path()).unwrap().compile.unwrap(); assert!(c.contains("target-feature=-crt-static"), "{c}"); } @@ -1359,7 +1359,7 @@ fn unique_out_dir( work_root: &Path, name: &str, h: &ArtifactHash, -) -> hammer_core::Result { +) -> takana_core::Result { let dir = work_root .join("out") .join(h.store_dir_name(name)); @@ -1378,7 +1378,7 @@ pub fn hydrate( target_fhs: &Path, mode: LinkMode, dynamic: Option<&hydrate::DynamicSpec>, -) -> hammer_core::Result { +) -> takana_core::Result { let artifact_dir = store.find_by_hash(h.as_str())?; hydrate::hydrate(&artifact_dir, target_fhs, mode, dynamic) } @@ -1417,8 +1417,8 @@ mod dep_hash_tests { write_recipe(d.path(), "app", "a0", &["base"]); write_recipe(d.path(), "app_nodep", "a0", &[]); // misma fuente, sin la dep - let with_dep = artifact_hash(&load(d.path(), "app"), &store, &hammer_core::lab::LabFingerprint::for_tests()).unwrap(); - let no_dep = artifact_hash(&load(d.path(), "app_nodep"), &store, &hammer_core::lab::LabFingerprint::for_tests()).unwrap(); + let with_dep = artifact_hash(&load(d.path(), "app"), &store, &takana_core::lab::LabFingerprint::for_tests()).unwrap(); + let no_dep = artifact_hash(&load(d.path(), "app_nodep"), &store, &takana_core::lab::LabFingerprint::for_tests()).unwrap(); // `app_nodep` se llama distinto, pero el nombre no entra al hash: la única diferencia // de entrada es la presencia de la dep. (Renombramos sólo para tener dos .toml.) assert_ne!(with_dep, no_dep, "la dep de build debe entrar al hash"); @@ -1431,11 +1431,11 @@ mod dep_hash_tests { write_recipe(d.path(), "base", "b0", &[]); write_recipe(d.path(), "lib", "l0", &["base"]); write_recipe(d.path(), "app", "a0", &["lib"]); - let before = artifact_hash(&load(d.path(), "app"), &store, &hammer_core::lab::LabFingerprint::for_tests()).unwrap(); + let before = artifact_hash(&load(d.path(), "app"), &store, &takana_core::lab::LabFingerprint::for_tests()).unwrap(); // Cambiar la fuente de la dep transitiva `base` debe re-hashear `app`. write_recipe(d.path(), "base", "b1", &[]); - let after = artifact_hash(&load(d.path(), "app"), &store, &hammer_core::lab::LabFingerprint::for_tests()).unwrap(); + let after = artifact_hash(&load(d.path(), "app"), &store, &takana_core::lab::LabFingerprint::for_tests()).unwrap(); assert_ne!(before, after, "un cambio transitivo debe propagarse"); } @@ -1444,7 +1444,7 @@ mod dep_hash_tests { let d = tempfile::tempdir().unwrap(); let store = store_in(d.path()); write_recipe(d.path(), "app", "a0", &["pcre2"]); // sin pcre2.toml - let err = artifact_hash(&load(d.path(), "app"), &store, &hammer_core::lab::LabFingerprint::for_tests()).unwrap_err().to_string(); + let err = artifact_hash(&load(d.path(), "app"), &store, &takana_core::lab::LabFingerprint::for_tests()).unwrap_err().to_string(); assert!(err.contains("pcre2"), "el error debe nombrar la dep: {err}"); assert!(err.contains("app"), "y la receta que la pide: {err}"); } @@ -1455,7 +1455,7 @@ mod dep_hash_tests { let store = store_in(d.path()); write_recipe(d.path(), "a", "a0", &["b"]); write_recipe(d.path(), "b", "b0", &["a"]); - let err = artifact_hash(&load(d.path(), "a"), &store, &hammer_core::lab::LabFingerprint::for_tests()).unwrap_err().to_string(); + let err = artifact_hash(&load(d.path(), "a"), &store, &takana_core::lab::LabFingerprint::for_tests()).unwrap_err().to_string(); assert!(err.contains("ciclo"), "esperaba ciclo: {err}"); assert!(err.contains("a -> b -> a"), "debe mostrar la cadena: {err}"); } @@ -1468,7 +1468,7 @@ mod dep_hash_tests { "name=\"x\"\nversion=\"1\"\n[source]\nrepo=\"git://x\"\ncommit=\"c0\"\n[build]\n[deps]\nbuild=[\"y\"]\n", ) .unwrap(); - let err = artifact_hash(&r, &store, &hammer_core::lab::LabFingerprint::for_tests()).unwrap_err().to_string(); + let err = artifact_hash(&r, &store, &takana_core::lab::LabFingerprint::for_tests()).unwrap_err().to_string(); assert!(err.contains("base_dir"), "debe explicar la falta de base_dir: {err}"); } @@ -1477,8 +1477,8 @@ mod dep_hash_tests { let d = tempfile::tempdir().unwrap(); let store = store_in(d.path()); write_recipe(d.path(), "solo", "s0", &[]); - let a = artifact_hash(&load(d.path(), "solo"), &store, &hammer_core::lab::LabFingerprint::for_tests()).unwrap(); - let b = artifact_hash(&load(d.path(), "solo"), &store, &hammer_core::lab::LabFingerprint::for_tests()).unwrap(); + let a = artifact_hash(&load(d.path(), "solo"), &store, &takana_core::lab::LabFingerprint::for_tests()).unwrap(); + let b = artifact_hash(&load(d.path(), "solo"), &store, &takana_core::lab::LabFingerprint::for_tests()).unwrap(); assert_eq!(a, b, "sin deps el hash es estable"); } } diff --git a/crates/hammer-build/src/sandbox.rs b/crates/takana-build/src/sandbox.rs similarity index 96% rename from crates/hammer-build/src/sandbox.rs rename to crates/takana-build/src/sandbox.rs index 60a551fa..ef5ae026 100644 --- a/crates/hammer-build/src/sandbox.rs +++ b/crates/takana-build/src/sandbox.rs @@ -18,7 +18,7 @@ use std::sync::{Arc, Mutex}; const TAIL_LINES: usize = 50; /// Fallo de una fase de build, con la cola del log del lab si la pudimos capturar. Viaja -/// dentro de `hammer_core::Error::Other(anyhow)`; el bus la recupera por `downcast_ref` para +/// dentro de `takana_core::Error::Other(anyhow)`; el bus la recupera por `downcast_ref` para /// poblar `Event::BuildFailed.log_tail`. Ver `docs/07-agent-bus.md`. #[derive(Debug, Clone)] pub struct BuildFailure { @@ -41,9 +41,9 @@ impl std::error::Error for BuildFailure {} impl BuildFailure { /// Recupera un `BuildFailure` de un error de hammer-core, si lo lleva dentro. El bus lo /// usa para separar `reason` de `log_tail`. - pub fn from_error(e: &hammer_core::Error) -> Option<&BuildFailure> { + pub fn from_error(e: &takana_core::Error) -> Option<&BuildFailure> { match e { - hammer_core::Error::Other(a) => a.downcast_ref::(), + takana_core::Error::Other(a) => a.downcast_ref::(), _ => None, } } @@ -87,8 +87,8 @@ impl Sandbox { /// Ejecuta `cmd` dentro del sandbox bajo `sh -c`. Hace *tee* de stdout/stderr al padre /// (para no perder el streaming en vivo) y a la vez retiene las últimas [`TAIL_LINES`] /// líneas; si el exit code es != 0, devuelve un [`BuildFailure`] con esa cola en - /// `log_tail`, envuelto en `hammer_core::Error::Other`. - pub fn run(&self, cmd: &str) -> hammer_core::Result<()> { + /// `log_tail`, envuelto en `takana_core::Error::Other`. + pub fn run(&self, cmd: &str) -> takana_core::Result<()> { // harkaq (SDD 16): sin HARKAQ=1 esto es `None` y todo lo de abajo es el camino de // siempre — mismos args de bwrap, mismo entorno, ningún proceso extra. Inerte por // requisito: hay 700+ artefactos sellados cuyo hash no puede moverse por encender un @@ -109,7 +109,7 @@ impl Sandbox { .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn bwrap: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn bwrap: {e}")))?; // Ring buffer compartido por ambos pumps: la cola combinada de stdout+stderr. let tail = Arc::new(Mutex::new(VecDeque::::with_capacity(TAIL_LINES))); @@ -120,7 +120,7 @@ impl Sandbox { let status = child .wait() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("wait bwrap: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("wait bwrap: {e}")))?; // Aseguramos drenar ambos streams antes de leer la cola. let _ = h_out.join(); let _ = h_err.join(); @@ -148,7 +148,7 @@ impl Sandbox { "build phase falló (exit {}): {cmd}", status.code().map(|c| c.to_string()).unwrap_or_else(|| "?".into()) ); - return Err(hammer_core::Error::Other(anyhow::Error::new(BuildFailure { + return Err(takana_core::Error::Other(anyhow::Error::new(BuildFailure { reason, log_tail: tail_str, }))); @@ -160,7 +160,7 @@ impl Sandbox { /// exit code en vez de fallar en != 0 — el caller decide contra lo esperado. El stderr se teea al /// padre en vivo (logging), como en `run`. Es el motor de ejecución del checker de evidencia (H1b): /// correr un `cmd` en el sandbox reproducible y comparar (exit, blake3(stdout)) contra lo declarado. - pub fn run_capture(&self, cmd: &str) -> hammer_core::Result { + pub fn run_capture(&self, cmd: &str) -> takana_core::Result { let args = self.bwrap_args(cmd); tracing::debug!(?args, "bwrap (capture)"); let mut child = Command::new("bwrap") @@ -169,7 +169,7 @@ impl Sandbox { .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("spawn bwrap: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("spawn bwrap: {e}")))?; let mut out = child.stdout.take().expect("stdout piped"); let err = child.stderr.take().expect("stderr piped"); @@ -184,7 +184,7 @@ impl Sandbox { let status = child .wait() - .map_err(|e| hammer_core::Error::Other(anyhow::anyhow!("wait bwrap: {e}")))?; + .map_err(|e| takana_core::Error::Other(anyhow::anyhow!("wait bwrap: {e}")))?; let stdout = h_out.join().unwrap_or_default(); let _ = h_err.join(); @@ -526,17 +526,17 @@ fn spawn_pump( } /// Errores tempranos: comprueba que las rutas base existen antes de invocar el build. -pub fn ensure_layout(rootfs: &Path, zig_dir: &Path) -> hammer_core::Result<()> { +pub fn ensure_layout(rootfs: &Path, zig_dir: &Path) -> takana_core::Result<()> { // bin/sh en Alpine es un symlink absoluto a /bin/busybox, que desde el host no resuelve. // Comprobamos el archivo regular real para no engañarnos. if !rootfs.join("bin/busybox").is_file() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "rootfs inválido: no encuentro {}/bin/busybox — ¿corriste el bootstrap de Alpine?", rootfs.display() ))); } if !zig_dir.join("zig").exists() { - return Err(hammer_core::Error::Other(anyhow::anyhow!( + return Err(takana_core::Error::Other(anyhow::anyhow!( "zig no encontrado en {}/zig — ¿instalaste zig en .dev-fs/tools/zig?", zig_dir.display() ))); @@ -597,11 +597,11 @@ pub const RANLIB_WRAPPER: &str = "ranlib"; /// (ejecutable estático / `.a`) el wrapper es TRANSPARENTE ⇒ byte-idéntico a `zig cc`, y el resto del /// árbol sigue estático. El ArtifactHash se deriva de inputs (receta+deps), no de los bytes ⇒ este /// cambio NO re-hashea nada sellado; sólo destraba builds nuevos con enlace dinámico irreducible. -fn write_cc_wrappers(rootfs: &Path) -> hammer_core::Result<()> { +fn write_cc_wrappers(rootfs: &Path) -> takana_core::Result<()> { use std::os::unix::fs::PermissionsExt; let bindir = rootfs.join("usr/local/bin"); std::fs::create_dir_all(&bindir).map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!("no pude crear {}: {e}", bindir.display())) + takana_core::Error::Other(anyhow::anyhow!("no pude crear {}: {e}", bindir.display())) })?; // `case " $* "` detecta como palabra los marcadores de "este link es dinámico": -shared, // -rdynamic, --export-dynamic, o un shared object en la línea (`…​.so ` final o `…​.so.N` versionado). @@ -636,10 +636,10 @@ fn write_cc_wrappers(rootfs: &Path) -> hammer_core::Result<()> { for (name, driver) in [(CC_WRAPPER, "zig cc"), (CXX_WRAPPER, "zig c++")] { let path = bindir.join(name); std::fs::write(&path, body(driver)).map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!("no pude escribir {}: {e}", path.display())) + takana_core::Error::Other(anyhow::anyhow!("no pude escribir {}: {e}", path.display())) })?; std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o755)).map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!("no pude chmod {}: {e}", path.display())) + takana_core::Error::Other(anyhow::anyhow!("no pude chmod {}: {e}", path.display())) })?; } @@ -658,10 +658,10 @@ fn write_cc_wrappers(rootfs: &Path) -> hammer_core::Result<()> { "#!/bin/sh\n # Interpuesto por hammer: fuerza archivos deterministas (sin hora de pared en la\n # cabecera `ar`). Sin esto dos builds idénticos sellan bytes distintos. Ver\n # sandbox.rs::AR_WRAPPER.\n [ -x /usr/bin/{tool} ] || exit 127\n exec /usr/bin/{tool} -D \"$@\"\n" ); std::fs::write(&path, body).map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!("no pude escribir {}: {e}", path.display())) + takana_core::Error::Other(anyhow::anyhow!("no pude escribir {}: {e}", path.display())) })?; std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o755)).map_err(|e| { - hammer_core::Error::Other(anyhow::anyhow!("no pude chmod {}: {e}", path.display())) + takana_core::Error::Other(anyhow::anyhow!("no pude chmod {}: {e}", path.display())) })?; } Ok(()) @@ -688,7 +688,7 @@ mod tests { reason: "exit 2".into(), log_tail: Some("undefined reference to `foo'".into()), }; - let err = hammer_core::Error::Other(anyhow::Error::new(bf)); + let err = takana_core::Error::Other(anyhow::Error::new(bf)); let recovered = BuildFailure::from_error(&err).expect("debe recuperarse"); assert_eq!(recovered.reason, "exit 2"); assert_eq!( @@ -699,7 +699,7 @@ mod tests { #[test] fn from_error_none_for_plain_errors() { - let err = hammer_core::Error::Recipe("nope".into()); + let err = takana_core::Error::Recipe("nope".into()); assert!(BuildFailure::from_error(&err).is_none()); } diff --git a/crates/hammer-build/src/swm_bridge.rs b/crates/takana-build/src/swm_bridge.rs similarity index 90% rename from crates/hammer-build/src/swm_bridge.rs rename to crates/takana-build/src/swm_bridge.rs index 5c5df20d..e03e400d 100644 --- a/crates/hammer-build/src/swm_bridge.rs +++ b/crates/takana-build/src/swm_bridge.rs @@ -1,4 +1,4 @@ -//! Puente entre `hammer_core::Mutation::SourcePatch` y el laboratorio. +//! Puente entre `takana_core::Mutation::SourcePatch` y el laboratorio. //! //! Convierte la mutación serializada en una `Recipe` efímera + un archivo de patch //! temporal, y delega en `build` para sellar el artefacto en el store. Luego se hidrata. @@ -9,7 +9,7 @@ use std::path::{Path, PathBuf}; -use hammer_core::{ +use takana_core::{ swm::{Mutation, SwmBuild}, ArtifactHash, Compiler, LinkMode, Recipe, Store, }; @@ -27,7 +27,7 @@ pub fn build_source_patch( store: &Store, scratch_root: Option<&Path>, name: Option<&str>, -) -> hammer_core::Result { +) -> takana_core::Result { let catalog_dir = catalog_dir_for(cfg, scratch_root); // El NOMBRE de la receta sintetizada decide el sufijo del store (`-`) Y la // clave de cache-hit (`store.has(hash, name)`). Si quien llama conoce el nombre del paquete @@ -47,7 +47,7 @@ pub fn build_source_patch( .strip_prefix("b3:") .expect("of_inputs siempre devuelve 'b3:'"); if want_hex != got_hex { - return Err(hammer_core::Error::Recipe(format!( + return Err(takana_core::Error::Recipe(format!( "expected_hash no coincide: declarado=b3:{want_hex}, obtenido={hash}" ))); } @@ -72,7 +72,7 @@ pub fn recipe_from_source_patch( mutation: &Mutation, name: Option<&str>, catalog_dir: &Path, -) -> hammer_core::Result { +) -> takana_core::Result { let (repo, commit, tarball, sha256, strip_components, patch, patch_url, build_cfg, target_bin, deps, evidence, slots) = match mutation { Mutation::SourcePatch { @@ -83,33 +83,33 @@ pub fn recipe_from_source_patch( target_bin, deps, evidence, slots, ), _ => { - return Err(hammer_core::Error::Recipe( + return Err(takana_core::Error::Recipe( "recipe_from_source_patch: la mutación no es 'source_patch'".into(), )); } }; // git xor tarball — misma regla que el schema (`swm_source_kind`). - let source_kind = hammer_core::swm::swm_source_kind( + let source_kind = takana_core::swm::swm_source_kind( repo.as_deref(), commit.as_deref(), tarball.as_deref(), sha256.as_deref(), ) - .map_err(hammer_core::Error::Recipe)?; + .map_err(takana_core::Error::Recipe)?; std::fs::create_dir_all(catalog_dir)?; // Clave estable del origen para nombrar el patch a disco: el commit (git) o el sha256 // (tarball). Idéntica reaplicación ⇒ mismo nombre ⇒ hash de receta determinista. let source_key: &str = match &source_kind { - hammer_core::SourceKind::Git { commit, .. } => commit, - hammer_core::SourceKind::Tarball { sha256, .. } => sha256, + takana_core::SourceKind::Git { commit, .. } => commit, + takana_core::SourceKind::Tarball { sha256, .. } => sha256, // Inalcanzable por construcción —`swm_source_kind` sólo produce Git o Tarball— pero se // escribe como error y no como `unreachable!`: esto es una librería, y un panic aquí // mataría al llamador por una receta mal formada en vez de decírselo. - hammer_core::SourceKind::Dir { .. } => { - return Err(hammer_core::Error::Recipe( + takana_core::SourceKind::Dir { .. } => { + return Err(takana_core::Error::Recipe( "un .swm no puede llevar un source por directorio".into(), )) } @@ -162,31 +162,31 @@ fn derive_name(target_bin: &str) -> String { #[allow(clippy::too_many_arguments)] fn synthesize_recipe( name: &str, - source: &hammer_core::SourceKind<'_>, + source: &takana_core::SourceKind<'_>, build_cfg: &SwmBuild, strip_components: Option, - deps: &hammer_core::Deps, - evidence: &hammer_core::Evidence, - slots: &hammer_core::Slots, + deps: &takana_core::Deps, + evidence: &takana_core::Evidence, + slots: &takana_core::Slots, patches: Vec, base_dir: &Path, -) -> hammer_core::Result { +) -> takana_core::Result { let compiler = parse_compiler(&build_cfg.compiler)?; let link = parse_link(&build_cfg.link)?; // Sección `[source]` y sufijo de versión según el modo de origen. El validador de // `Source::kind` ya garantiza git xor tarball; acá sólo emitimos el TOML correspondiente. let (version_key, source_block) = match source { - hammer_core::SourceKind::Git { repo, commit } => ( + takana_core::SourceKind::Git { repo, commit } => ( *commit, format!("repo = \"{repo}\"\ncommit = \"{commit}\"\n"), ), - hammer_core::SourceKind::Tarball { url, sha256 } => ( + takana_core::SourceKind::Tarball { url, sha256 } => ( *sha256, format!("tarball = \"{url}\"\nsha256 = \"{sha256}\"\n"), ), // Ver la nota del `source_key` de arriba: un `.swm` no puede traer un `dir`. - hammer_core::SourceKind::Dir { .. } => { - return Err(hammer_core::Error::Recipe( + takana_core::SourceKind::Dir { .. } => { + return Err(takana_core::Error::Recipe( "un .swm no puede llevar un source por directorio".into(), )) } @@ -241,22 +241,22 @@ flags = [] Ok(recipe) } -fn parse_compiler(s: &str) -> hammer_core::Result { +fn parse_compiler(s: &str) -> takana_core::Result { match s { "zig-cc" => Ok(Compiler::ZigCc), "clang" => Ok(Compiler::Clang), "gcc" => Ok(Compiler::Gcc), - other => Err(hammer_core::Error::Recipe(format!( + other => Err(takana_core::Error::Recipe(format!( "compiler desconocido: '{other}' (esperado zig-cc/clang/gcc)" ))), } } -fn parse_link(s: &str) -> hammer_core::Result { +fn parse_link(s: &str) -> takana_core::Result { match s { "static" => Ok(LinkMode::Static), "dynamic" => Ok(LinkMode::Dynamic), - other => Err(hammer_core::Error::Recipe(format!( + other => Err(takana_core::Error::Recipe(format!( "link desconocido: '{other}' (esperado static/dynamic)" ))), } @@ -284,9 +284,9 @@ logo = "b3:azul" [slots.requires] "wayland-protocol" = "b3:stock" "#; - let recipe = hammer_core::Recipe::from_toml(toml).unwrap(); + let recipe = takana_core::Recipe::from_toml(toml).unwrap(); let swm = - hammer_core::Swm::from_recipe(&recipe, "/usr/bin/tema", None, None, "2026-06-06").unwrap(); + takana_core::Swm::from_recipe(&recipe, "/usr/bin/tema", None, None, "2026-06-06").unwrap(); // El .swm YAML debe llevar el bloque slots. let yaml = swm.to_yaml().unwrap(); assert!(yaml.contains("slots"), "el .swm debe transportar slots: {yaml}"); @@ -327,15 +327,15 @@ logo = "b3:azul" let d = tempfile::tempdir().unwrap(); let r = synthesize_recipe( "grep", - &hammer_core::SourceKind::Git { + &takana_core::SourceKind::Git { repo: "git://example/grep.git", commit: "a1b2c3d4e5f6a7b8c9", }, &fake_swm_build(), None, - &hammer_core::Deps::default(), - &hammer_core::Evidence::default(), - &hammer_core::Slots::default(), + &takana_core::Deps::default(), + &takana_core::Evidence::default(), + &takana_core::Slots::default(), vec![], d.path(), ) @@ -344,7 +344,7 @@ logo = "b3:azul" assert!(r.version.starts_with("swm-a1b2c3d4")); assert_eq!(r.build.flags, vec!["--enable-foo"]); match r.source.kind().unwrap() { - hammer_core::SourceKind::Git { repo, commit } => { + takana_core::SourceKind::Git { repo, commit } => { assert_eq!(repo, "git://example/grep.git"); assert_eq!(commit, "a1b2c3d4e5f6a7b8c9"); } @@ -357,15 +357,15 @@ logo = "b3:azul" let d = tempfile::tempdir().unwrap(); let r = synthesize_recipe( "grep", - &hammer_core::SourceKind::Tarball { + &takana_core::SourceKind::Tarball { url: "https://ftp.gnu.org/gnu/grep/grep-3.11.tar.gz", sha256: "abcdef0123456789", }, &fake_swm_build(), None, - &hammer_core::Deps::default(), - &hammer_core::Evidence::default(), - &hammer_core::Slots::default(), + &takana_core::Deps::default(), + &takana_core::Evidence::default(), + &takana_core::Slots::default(), vec![], d.path(), ) @@ -373,7 +373,7 @@ logo = "b3:azul" assert_eq!(r.name, "grep"); assert!(r.version.starts_with("swm-abcdef012345")); match r.source.kind().unwrap() { - hammer_core::SourceKind::Tarball { url, sha256 } => { + takana_core::SourceKind::Tarball { url, sha256 } => { assert_eq!(url, "https://ftp.gnu.org/gnu/grep/grep-3.11.tar.gz"); assert_eq!(sha256, "abcdef0123456789"); } diff --git a/crates/hammer-build/tests/end_to_end_autotools.rs b/crates/takana-build/tests/end_to_end_autotools.rs similarity index 98% rename from crates/hammer-build/tests/end_to_end_autotools.rs rename to crates/takana-build/tests/end_to_end_autotools.rs index 3c8bb14c..0b89c77c 100644 --- a/crates/hammer-build/tests/end_to_end_autotools.rs +++ b/crates/takana-build/tests/end_to_end_autotools.rs @@ -9,8 +9,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; -use hammer_build::{build, BuildConfig}; -use hammer_core::{Recipe, Store}; +use takana_build::{build, BuildConfig}; +use takana_core::{Recipe, Store}; const HELLO_C: &str = r#" #include diff --git a/crates/hammer-build/tests/end_to_end_grep.rs b/crates/takana-build/tests/end_to_end_grep.rs similarity index 98% rename from crates/hammer-build/tests/end_to_end_grep.rs rename to crates/takana-build/tests/end_to_end_grep.rs index a7a43f63..1983f654 100644 --- a/crates/hammer-build/tests/end_to_end_grep.rs +++ b/crates/takana-build/tests/end_to_end_grep.rs @@ -11,8 +11,8 @@ use std::path::PathBuf; use std::process::Command; -use hammer_build::{build, run_hydrate, BuildConfig}; -use hammer_core::{LinkMode, Recipe, Store}; +use takana_build::{build, run_hydrate, BuildConfig}; +use takana_core::{LinkMode, Recipe, Store}; const RECIPE_TOML: &str = r#" name = "grep" diff --git a/crates/hammer-build/tests/end_to_end_hello.rs b/crates/takana-build/tests/end_to_end_hello.rs similarity index 97% rename from crates/hammer-build/tests/end_to_end_hello.rs rename to crates/takana-build/tests/end_to_end_hello.rs index efe2f5b9..4c03427c 100644 --- a/crates/hammer-build/tests/end_to_end_hello.rs +++ b/crates/takana-build/tests/end_to_end_hello.rs @@ -1,7 +1,7 @@ //! Integration test del pipeline completo de Fase 0: //! 1. Inicializa un repo git local con un `hello.c`. //! 2. Escribe una receta TOML que apunta a ese repo con phases override. -//! 3. Llama a `hammer_build::build` con un store/work temporales. +//! 3. Llama a `takana_build::build` con un store/work temporales. //! 4. Verifica que el artefacto sellado contiene `usr/bin/hello`, es ELF estático y //! se ejecuta dentro del sandbox imprimiendo el output esperado. //! @@ -12,8 +12,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; -use hammer_build::{build, BuildConfig}; -use hammer_core::{Recipe, Store}; +use takana_build::{build, BuildConfig}; +use takana_core::{Recipe, Store}; const HELLO_C: &str = r#" #include diff --git a/crates/hammer-build/tests/fetch_tarball.rs b/crates/takana-build/tests/fetch_tarball.rs similarity index 98% rename from crates/hammer-build/tests/fetch_tarball.rs rename to crates/takana-build/tests/fetch_tarball.rs index d8b31f77..8de65ed2 100644 --- a/crates/hammer-build/tests/fetch_tarball.rs +++ b/crates/takana-build/tests/fetch_tarball.rs @@ -4,7 +4,7 @@ //! - Genero un tarball en un tempdir con contenido conocido. //! - Calculo su sha256 real con la misma crate (`sha2`) que usa el fetch. //! - Sirvo el tarball vía URL `file://` (curl la maneja nativamente). -//! - Llamo a `hammer_build::fetch::fetch` con una receta TOML que apunta a esa URL. +//! - Llamo a `takana_build::fetch::fetch` con una receta TOML que apunta a esa URL. //! //! Cubre: happy path con strip_components, mismatch de sha256 no envenena la caché, reuso //! de caché en segunda llamada, strip_components = 0 vs 1. @@ -12,8 +12,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; -use hammer_build::fetch::fetch; -use hammer_core::Recipe; +use takana_build::fetch::fetch; +use takana_core::Recipe; use sha2::{Digest, Sha256}; /// Crea `/inner/{a.txt,sub/b.txt}` y empaqueta `inner/` en `/payload.tar.gz`. diff --git a/crates/hammer-build/tests/hidratacion_no_escapa.rs b/crates/takana-build/tests/hidratacion_no_escapa.rs similarity index 98% rename from crates/hammer-build/tests/hidratacion_no_escapa.rs rename to crates/takana-build/tests/hidratacion_no_escapa.rs index ea521202..212cdb36 100644 --- a/crates/hammer-build/tests/hidratacion_no_escapa.rs +++ b/crates/takana-build/tests/hidratacion_no_escapa.rs @@ -12,8 +12,8 @@ use std::path::Path; -use hammer_build::hydrate::hydrate; -use hammer_core::LinkMode; +use takana_build::hydrate::hydrate; +use takana_core::LinkMode; /// Artefacto que trae `usr/share/pkg` como symlink a `destino`. fn artefacto_con_symlink(dir: &Path, destino: &Path) { diff --git a/crates/hammer-build/tests/sin_pre_exec.rs b/crates/takana-build/tests/sin_pre_exec.rs similarity index 100% rename from crates/hammer-build/tests/sin_pre_exec.rs rename to crates/takana-build/tests/sin_pre_exec.rs diff --git a/crates/hammer-cli/Cargo.toml b/crates/takana-cli/Cargo.toml similarity index 79% rename from crates/hammer-cli/Cargo.toml rename to crates/takana-cli/Cargo.toml index b079d684..4dce9724 100644 --- a/crates/hammer-cli/Cargo.toml +++ b/crates/takana-cli/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-cli" +name = "takana-cli" version.workspace = true edition.workspace = true license.workspace = true @@ -23,17 +23,17 @@ path = "src/main.rs" default = [] # Activa el traductor LLM real (Claude API) detrás del flag `hammer ai --llm`. # Sin esta feature, `--llm` falla con un mensaje claro pidiendo recompilar. -llm-claude = ["hammer-agent/llm-claude"] +llm-claude = ["takana-agent/llm-claude"] [dependencies] -hammer-core.workspace = true -hammer-build.workspace = true -hammer-bootstrap.workspace = true -hammer-mirror.workspace = true -hammer-upgrade.workspace = true -hammer-overlay.workspace = true -hammer-journal.workspace = true -hammer-agent.workspace = true +takana-core.workspace = true +takana-build.workspace = true +takana-bootstrap.workspace = true +takana-mirror.workspace = true +takana-upgrade.workspace = true +takana-overlay.workspace = true +takana-journal.workspace = true +takana-agent.workspace = true serde.workspace = true serde_json.workspace = true toml.workspace = true diff --git a/crates/hammer-cli/src/alpine_import.rs b/crates/takana-cli/src/alpine_import.rs similarity index 99% rename from crates/hammer-cli/src/alpine_import.rs rename to crates/takana-cli/src/alpine_import.rs index 9e517f45..fb6e41e0 100644 --- a/crates/hammer-cli/src/alpine_import.rs +++ b/crates/takana-cli/src/alpine_import.rs @@ -334,7 +334,7 @@ package() { #[test] fn extracts_source_patches_deps_phases() { let toml = recipe_from_apkbuild(APKBUILD_PATCHED).unwrap(); - let recipe = hammer_core::Recipe::from_toml(&toml).expect("recipe válida"); + let recipe = takana_core::Recipe::from_toml(&toml).expect("recipe válida"); assert_eq!(recipe.name, "foo"); assert_eq!(recipe.version, "2.5"); // tarball con $pkgver expandido: @@ -378,7 +378,7 @@ package() { #[test] fn no_patches_is_empty() { let apk = "pkgname=zlib\npkgver=1.3\nsource=\"https://zlib.net/zlib-$pkgver.tar.gz\"\nsha512sums=\"x z\"\n"; - let recipe = hammer_core::Recipe::from_toml(&recipe_from_apkbuild(apk).unwrap()).unwrap(); + let recipe = takana_core::Recipe::from_toml(&recipe_from_apkbuild(apk).unwrap()).unwrap(); assert_eq!(recipe.name, "zlib"); assert!(recipe.source.patches.is_empty()); assert_eq!(recipe.source.tarball.as_deref(), Some("https://zlib.net/zlib-1.3.tar.gz")); diff --git a/crates/hammer-cli/src/kernel_cmd.rs b/crates/takana-cli/src/kernel_cmd.rs similarity index 95% rename from crates/hammer-cli/src/kernel_cmd.rs rename to crates/takana-cli/src/kernel_cmd.rs index 5f39e17d..6226d961 100644 --- a/crates/hammer-cli/src/kernel_cmd.rs +++ b/crates/takana-cli/src/kernel_cmd.rs @@ -8,8 +8,8 @@ use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; use clap::Subcommand; -use hammer_core::kernel::kconfig::KconfigTree; -use hammer_core::kernel::KernelConfig; +use takana_core::kernel::kconfig::KconfigTree; +use takana_core::kernel::KernelConfig; use serde::Serialize; /// Dónde busca el árbol de Kconfig si no se pasa `--kconfig`. @@ -425,7 +425,7 @@ struct ClosureReport { /// De la clausura, los que un humano puede marcar en `menuconfig`. visible: usize, /// `select` que entran desde fuera: reencienden algo de la clausura ignorando sus `depends on`. - leaks: Vec, + leaks: Vec, /// Símbolos distintos de la clausura alcanzados por esas fugas. leaked_targets: usize, #[serde(skip_serializing_if = "Option::is_none")] @@ -447,7 +447,7 @@ struct FixpointReport { /// Lo que hubo que apagar de más, con la ronda en que apareció. added: Vec<(usize, String)>, /// Fugas que sobrevivieron al tope de rondas. Vacío = cerró. - remaining_leaks: Vec, + remaining_leaks: Vec, } /// Contraste contra un `.config` real: la validación §3 del SDD 22. @@ -520,7 +520,7 @@ fn closure( let on: Vec = cl.iter().filter(|s| cfg.is_on(s)).cloned().collect(); let off = cl .iter() - .filter(|s| matches!(cfg.get(s), Some(hammer_core::kernel::ConfigValue::No))) + .filter(|s| matches!(cfg.get(s), Some(takana_core::kernel::ConfigValue::No))) .count(); let absent = cl.iter().filter(|s| cfg.get(s).is_none()).count(); Some(AgainstReport { @@ -644,7 +644,7 @@ fn probe( with_hw: bool, json: bool, ) -> Result<()> { - use hammer_core::kernel::reverse::{BundleState, HwSignal}; + use takana_core::kernel::reverse::{BundleState, HwSignal}; let cfg_path = match config { Some(p) => p.to_path_buf(), @@ -655,9 +655,9 @@ fn probe( anyhow::bail!("{} no tiene un solo CONFIG_*: ¿es un .config?", cfg_path.display()); } let tree = load_tree(kroot)?; - let cat = hammer_core::kernel::Catalog::load(catalog)?; - let hw = with_hw.then(hammer_core::kernel::Hardware::probe_local); - let rep = hammer_core::kernel::reverse::analyze(&cat, &tree, &cfg, hw.as_ref()); + let cat = takana_core::kernel::Catalog::load(catalog)?; + let hw = with_hw.then(takana_core::kernel::Hardware::probe_local); + let rep = takana_core::kernel::reverse::analyze(&cat, &tree, &cfg, hw.as_ref()); if json { println!("{}", serde_json::to_string_pretty(&rep)?); @@ -793,7 +793,7 @@ struct BundleView { closure_len: usize, visible: usize, unknown_symbols: Vec, - undeclared_leaks: Vec, + undeclared_leaks: Vec, accepted_leaks: usize, } @@ -811,7 +811,7 @@ struct BundlesReport { struct KnobView { id: String, title: String, - side: hammer_core::kernel::Side, + side: takana_core::kernel::Side, enable: Vec, disable: Vec, #[serde(skip_serializing_if = "Option::is_none")] @@ -821,7 +821,7 @@ struct KnobView { fn bundles(kroot: &Path, catalog: &Path, check: bool, json: bool) -> Result<()> { let tree = load_tree(kroot)?; - let cat = hammer_core::kernel::Catalog::load(catalog)?; + let cat = takana_core::kernel::Catalog::load(catalog)?; let mut views = Vec::new(); for b in &cat.bundles { @@ -932,17 +932,17 @@ fn bundles(kroot: &Path, catalog: &Path, check: bool, json: bool) -> Result<()> println!("NIVEL 2 — política y rendimiento (ojo al lado del que cae cada perilla)"); for k in &rep.knobs { let lado = match k.side { - hammer_core::kernel::Side::Kconfig => "kconfig", - hammer_core::kernel::Side::Recipe => "receta ", + takana_core::kernel::Side::Kconfig => "kconfig", + takana_core::kernel::Side::Recipe => "receta ", }; let que = match k.side { - hammer_core::kernel::Side::Kconfig => { + takana_core::kernel::Side::Kconfig => { let mut v: Vec = k.enable.iter().map(|s| format!("+{s}")).collect(); v.extend(k.disable.iter().map(|s| format!("-{s}"))); v.join(" ") } - hammer_core::kernel::Side::Recipe => { + takana_core::kernel::Side::Recipe => { k.recipe_field.clone().unwrap_or_default() } }; @@ -988,9 +988,9 @@ fn plan( if bundle_ids.is_empty() && knob_ids.is_empty() { anyhow::bail!("un plan sin bundles ni perillas es la receta base: pasá --bundle/--knob"); } - let base = hammer_core::Recipe::load_from_path(recipe_path)?; + let base = takana_core::Recipe::load_from_path(recipe_path)?; let tree = load_tree(kroot)?; - let cat = hammer_core::kernel::Catalog::load(catalog)?; + let cat = takana_core::kernel::Catalog::load(catalog)?; // Las recetas de kernel del repo NO son todas la misma versión (`linux`/`linux-metal` van por // 6.16.12; `linux-metal-dual`/`linux-generic` por 7.1.2). Planear una contra el árbol de la otra @@ -1015,7 +1015,7 @@ fn plan( Some(_) => {} } - let mut p = hammer_core::kernel::plan::make_plan( + let mut p = takana_core::kernel::plan::make_plan( &base, &recipe_path.display().to_string(), &cat, @@ -1027,14 +1027,14 @@ fn plan( // El plan DETERMINA el artefacto (SDD 22 §1), así que el hash va en el plan: la UI puede decir // «esto ya está construido y firmado» sin construir nada. Si las deps no están resueltas, se // dice que no se pudo en vez de emitir un hash inventado. - let derived = hammer_core::kernel::plan::derive_recipe(&base, &p); - match hammer_core::Store::open(Path::new(store)) + let derived = takana_core::kernel::plan::derive_recipe(&base, &p); + match takana_core::Store::open(Path::new(store)) .map_err(anyhow::Error::from) .and_then(|s| { - let cfg = hammer_build::BuildConfig::from_env_or_defaults(s.root()); - let lab = hammer_core::lab::LabFingerprint::from_rootfs(&cfg.rootfs) + let cfg = takana_build::BuildConfig::from_env_or_defaults(s.root()); + let lab = takana_core::lab::LabFingerprint::from_rootfs(&cfg.rootfs) .map_err(anyhow::Error::from)?; - hammer_build::artifact_hash(&derived, &s, &lab).map_err(anyhow::Error::from) + takana_build::artifact_hash(&derived, &s, &lab).map_err(anyhow::Error::from) }) { Ok(h) => p.artifact_hash = Some(h.to_string()), @@ -1065,7 +1065,7 @@ fn plan( .map(|d| d.display().to_string()) .unwrap_or_default(), ); - let cuerpo = hammer_core::kernel::plan::render_recipe_toml(&derived)?; + let cuerpo = takana_core::kernel::plan::render_recipe_toml(&derived)?; std::fs::write(ro, format!("{cabecera}{cuerpo}")) .with_context(|| format!("escribiendo {}", ro.display()))?; } @@ -1091,8 +1091,8 @@ fn plan( println!("(se emiten RAÍCES: la clausura la calcula el olddefconfig del propio kernel)"); for s in &p.symbols { let signo = match s.action { - hammer_core::kernel::plan::Action::Enable => "+", - hammer_core::kernel::plan::Action::Disable => "-", + takana_core::kernel::plan::Action::Enable => "+", + takana_core::kernel::plan::Action::Disable => "-", }; println!(" {signo}{:<24} ← {} ({})", s.symbol, s.from, s.reason); } @@ -1121,7 +1121,7 @@ fn plan( } fn diff_back(plan_path: &Path, config: &Path, json: bool) -> Result<()> { - let p: hammer_core::kernel::Plan = serde_json::from_str( + let p: takana_core::kernel::Plan = serde_json::from_str( &std::fs::read_to_string(plan_path) .with_context(|| format!("leyendo {}", plan_path.display()))?, ) @@ -1130,7 +1130,7 @@ fn diff_back(plan_path: &Path, config: &Path, json: bool) -> Result<()> { if cfg.is_empty() { anyhow::bail!("{} no tiene un solo CONFIG_*: ¿es un .config?", config.display()); } - let d = hammer_core::kernel::diff_back(&p, &cfg); + let d = takana_core::kernel::diff_back(&p, &cfg); if json { println!("{}", serde_json::to_string_pretty(&d)?); @@ -1167,7 +1167,7 @@ fn diff_back(plan_path: &Path, config: &Path, json: bool) -> Result<()> { // --------------------------------------------------------------------------------------------- fn hw(out: Option<&Path>) -> Result<()> { - let h = hammer_core::kernel::Hardware::probe_local(); + let h = takana_core::kernel::Hardware::probe_local(); let texto = serde_json::to_string_pretty(&h)?; match out { Some(o) => { @@ -1201,7 +1201,7 @@ fn gate( if plan_path.is_none() && config.is_none() { anyhow::bail!("pasá --plan (qué apagaría) o --config (qué quedó): sin uno de los dos no hay nada que comparar"); } - let p: Option = match plan_path { + let p: Option = match plan_path { None => None, Some(pp) => Some( serde_json::from_str( @@ -1210,9 +1210,9 @@ fn gate( .with_context(|| format!("{} no es un plan de `hammer kernel plan`", pp.display()))?, ), }; - let cat = hammer_core::kernel::Catalog::load(catalog)?; + let cat = takana_core::kernel::Catalog::load(catalog)?; let tree = load_tree(kroot)?; - let modmap = hammer_core::kernel::ModMap::parse(kroot) + let modmap = takana_core::kernel::ModMap::parse(kroot) .with_context(|| format!("leyendo los Makefiles de {}", kroot.display()))?; if modmap.is_empty() { anyhow::bail!( @@ -1223,11 +1223,11 @@ fn gate( } let hardware = match devices { - Some(d) => serde_json::from_str::( + Some(d) => serde_json::from_str::( &std::fs::read_to_string(d).with_context(|| format!("leyendo {}", d.display()))?, ) .with_context(|| format!("{} no es un volcado de `hammer kernel hw`", d.display()))?, - None => hammer_core::kernel::Hardware::probe_local(), + None => takana_core::kernel::Hardware::probe_local(), }; let r = match config { @@ -1242,7 +1242,7 @@ fn gate( anyhow::bail!("{} no tiene un solo CONFIG_*: ¿es un .config?", c.display()); } println!("referente {} ({} símbolos)", base_path.display(), base.len()); - hammer_core::kernel::gate::run_against_config( + takana_core::kernel::gate::run_against_config( &base, &nuevo, &cat, @@ -1253,7 +1253,7 @@ fn gate( Some(&tree), )? } - None => hammer_core::kernel::gate::run( + None => takana_core::kernel::gate::run( p.as_ref().expect("validado arriba"), &cat, &tree, @@ -1312,7 +1312,7 @@ fn gate( } } - if r.verdict == hammer_core::kernel::Verdict::Bloquea { + if r.verdict == takana_core::kernel::Verdict::Bloquea { anyhow::bail!("el gate bloquea"); } Ok(()) @@ -1370,10 +1370,10 @@ fn deps_resuelven_desde(dir: &Path, deps: &[String]) -> bool { /// Primero por convención (`/.toml`) y sólo si eso no da, barriendo el directorio: /// **el artefacto se nombra por el campo `name`, no por el fichero**, y en este corpus hay recetas /// donde los dos difieren. -fn receta_de(artifact: &str, dirs: &[PathBuf]) -> Option { +fn receta_de(artifact: &str, dirs: &[PathBuf]) -> Option { for d in dirs { let directo = d.join(format!("{artifact}.toml")); - if let Ok(r) = hammer_core::Recipe::load_from_path(&directo) { + if let Ok(r) = takana_core::Recipe::load_from_path(&directo) { if r.name == artifact { return Some(con_catalogo(r, dirs)); } @@ -1382,7 +1382,7 @@ fn receta_de(artifact: &str, dirs: &[PathBuf]) -> Option { for e in rd.flatten() { let p = e.path(); if p.extension().is_some_and(|x| x == "toml") { - if let Ok(r) = hammer_core::Recipe::load_from_path(&p) { + if let Ok(r) = takana_core::Recipe::load_from_path(&p) { if r.name == artifact { return Some(con_catalogo(r, dirs)); } @@ -1404,7 +1404,7 @@ fn receta_de(artifact: &str, dirs: &[PathBuf]) -> Option { /// /// NO se toca si la receta trae `patches`: `base_dir` también los resuelve, y moverlo los rompería /// en silencio. Ahí es mejor no saber la vigencia (se comprueba todo) que hashear otra cosa. -fn con_catalogo(mut r: hammer_core::Recipe, dirs: &[PathBuf]) -> hammer_core::Recipe { +fn con_catalogo(mut r: takana_core::Recipe, dirs: &[PathBuf]) -> takana_core::Recipe { if r.deps.build.is_empty() || deps_resuelven_desde(&r.base_dir, &r.deps.build) { return r; } @@ -1434,13 +1434,13 @@ fn con_catalogo(mut r: hammer_core::Recipe, dirs: &[PathBuf]) -> hammer_core::Re /// lab de hoy — o sea que un kernel sellado con otro rootfs también sale superado, y es correcto /// (SDD 25: el lab entra en el artefacto). fn dirs_vigentes( - c: &hammer_core::kernel::Contract, + c: &takana_core::kernel::Contract, dirs: &[PathBuf], store: &str, ) -> Result> { - let st = hammer_core::Store::open(Path::new(store))?; - let cfg = hammer_build::BuildConfig::from_env_or_defaults(st.root()); - let lab = hammer_core::lab::LabFingerprint::from_rootfs(&cfg.rootfs)?; + let st = takana_core::Store::open(Path::new(store))?; + let cfg = takana_build::BuildConfig::from_env_or_defaults(st.root()); + let lab = takana_core::lab::LabFingerprint::from_rootfs(&cfg.rootfs)?; let mut out = std::collections::BTreeMap::new(); for t in &c.targets { let Some(r) = receta_de(&t.artifact, dirs) else { @@ -1451,7 +1451,7 @@ fn dirs_vigentes( ); continue; }; - match hammer_build::artifact_hash(&r, &st, &lab) { + match takana_build::artifact_hash(&r, &st, &lab) { Ok(h) => { out.insert(t.artifact.clone(), h.store_dir_name(&r.name)); } @@ -1464,10 +1464,10 @@ fn dirs_vigentes( #[derive(Serialize)] struct ContractRun { contract: String, - reports: Vec, + reports: Vec, /// Sellados que la receta de HOY ya no produce. Se informan y no bloquean: ver `dirs_vigentes`. #[serde(default)] - superados: Vec, + superados: Vec, /// Configs que NO se comprobaron por no tener perfil declarado. No cuentan como aprobados. sin_perfil: Vec, /// Objetivos del contrato cuya receta de hoy NO tiene ni un sellado en el store. No se @@ -1486,8 +1486,8 @@ fn contract_cmd( list: bool, json: bool, ) -> Result<()> { - use hammer_core::kernel::contract::sealed_kernel_configs; - use hammer_core::kernel::Contract; + use takana_core::kernel::contract::sealed_kernel_configs; + use takana_core::kernel::Contract; let c = Contract::load(contract)?; @@ -1501,7 +1501,7 @@ fn contract_cmd( println!("revisado contra kernel {r}"); } println!(); - let req = hammer_core::kernel::contract::required_by(&c); + let req = takana_core::kernel::contract::required_by(&c); for cap in &c.capabilities { let quien = req.get(cap.id.as_str()).map(|v| v.join(", ")).unwrap_or_default(); let quien = if quien.is_empty() { "—".to_string() } else { quien }; @@ -1586,7 +1586,7 @@ fn contract_cmd( }; for (label, artifact, path) in &objetivos { - let cfg = hammer_core::kernel::KernelConfig::parse(&read_maybe_gz(path)?); + let cfg = takana_core::kernel::KernelConfig::parse(&read_maybe_gz(path)?); if cfg.is_empty() { anyhow::bail!("{} no tiene un solo CONFIG_*: ¿es un .config?", path.display()); } @@ -1634,7 +1634,7 @@ fn contract_cmd( let bloquean = run .reports .iter() - .filter(|r| r.verdict == hammer_core::kernel::Verdict::Bloquea) + .filter(|r| r.verdict == takana_core::kernel::Verdict::Bloquea) .count(); if bloquean > 0 { anyhow::bail!("el contrato NO se cumple en {bloquean} kernel(es)"); @@ -1655,7 +1655,7 @@ fn imprimir_contrato(run: &ContractRun) { println!("contrato {}", run.contract); println!(); for r in &run.reports { - let marca = if r.verdict == hammer_core::kernel::Verdict::Bloquea { "✗" } else { "✓" }; + let marca = if r.verdict == takana_core::kernel::Verdict::Bloquea { "✗" } else { "✓" }; println!("{marca} {}", r.config); println!(" perfil {} ({} capacidad(es) miradas)", r.profile, r.checked); if let Some(k) = &r.kernel { @@ -1699,13 +1699,13 @@ fn imprimir_contrato(run: &ContractRun) { let malos = run .reports .iter() - .filter(|r| r.verdict == hammer_core::kernel::Verdict::Bloquea) + .filter(|r| r.verdict == takana_core::kernel::Verdict::Bloquea) .count(); if !run.superados.is_empty() { let sup_malos = run .superados .iter() - .filter(|r| r.verdict == hammer_core::kernel::Verdict::Bloquea) + .filter(|r| r.verdict == takana_core::kernel::Verdict::Bloquea) .count(); println!( "· {} sellado(s) SUPERADO(s) por la receta de hoy — no bloquean, {} con faltas:", diff --git a/crates/hammer-cli/src/main.rs b/crates/takana-cli/src/main.rs similarity index 89% rename from crates/hammer-cli/src/main.rs rename to crates/takana-cli/src/main.rs index 398fe311..866c2a6a 100644 --- a/crates/hammer-cli/src/main.rs +++ b/crates/takana-cli/src/main.rs @@ -272,7 +272,7 @@ enum Cmd { #[arg(long)] state_root: Option, /// Base de datos de instalados donde registrar el paquete (para `uninstall`). - #[arg(long, default_value = hammer_core::installed::DEFAULT_DB)] + #[arg(long, default_value = takana_core::installed::DEFAULT_DB)] db: PathBuf, /// Modo estricto: abortar si el release del repo no está firmado por una clave confiada /// (no basta con que el `.swm` reproduzca — exige autoría del catálogo verificada). @@ -290,12 +290,12 @@ enum Cmd { /// Nombre del paquete a desinstalar. name: String, /// Base de datos de instalados. - #[arg(long, default_value = hammer_core::installed::DEFAULT_DB)] + #[arg(long, default_value = takana_core::installed::DEFAULT_DB)] db: PathBuf, }, /// [Etapa F] Lista los paquetes instalados (de la DB). Installed { - #[arg(long, default_value = hammer_core::installed::DEFAULT_DB)] + #[arg(long, default_value = takana_core::installed::DEFAULT_DB)] db: PathBuf, }, /// [H4d] BÚSQUEDA de compatibilidad: particiona un repo entero contra el estado instalado en @@ -306,7 +306,7 @@ enum Cmd { #[arg(long, default_value = DEFAULT_REPO)] repo: String, /// Base de datos de instalados contra la que evaluar. - #[arg(long, default_value = hammer_core::installed::DEFAULT_DB)] + #[arg(long, default_value = takana_core::installed::DEFAULT_DB)] db: PathBuf, }, /// [Etapa G] Importa una receta DESDE nixpkgs: toma el JSON normalizado que produce @@ -433,7 +433,7 @@ enum Cmd { #[arg(long, default_value = "/", global = true)] root: String, /// Directorio de estado de generaciones (default `/var/lib/hammer/upgrades`). - #[arg(long, default_value = hammer_upgrade::DEFAULT_STATE_ROOT, global = true)] + #[arg(long, default_value = takana_upgrade::DEFAULT_STATE_ROOT, global = true)] state_root: String, /// Diario donde registrar cada cambio (default `/var/lib/hammer/journal`). #[arg(long, default_value = "/var/lib/hammer/journal", global = true)] @@ -449,7 +449,7 @@ enum Cmd { #[arg(long, default_value = "/", global = true)] root: String, /// Directorio de estado de generaciones (default `/var/lib/hammer/upgrades`). - #[arg(long, default_value = hammer_upgrade::DEFAULT_STATE_ROOT, global = true)] + #[arg(long, default_value = takana_upgrade::DEFAULT_STATE_ROOT, global = true)] state_root: String, /// Diario donde registrar cada cambio al activar (default `/var/lib/hammer/journal`). #[arg(long, default_value = "/var/lib/hammer/journal", global = true)] @@ -479,7 +479,7 @@ enum BootCmd { /// dibuje el menú. Regenerable, world-readable. Graph { /// Path de salida del grafo. - #[arg(long, default_value = hammer_upgrade::boot_graph::BOOT_GRAPH_PATH)] + #[arg(long, default_value = takana_upgrade::boot_graph::BOOT_GRAPH_PATH)] out: PathBuf, /// En vez de escribir el fichero, imprime el grafo por stdout (para inspección/tests). #[arg(long)] @@ -500,7 +500,7 @@ enum BootCmd { #[arg(long)] from_select: bool, /// Path del canal de vuelta que deja mirada. - #[arg(long, default_value = hammer_upgrade::boot_graph::BOOT_SELECT_PATH)] + #[arg(long, default_value = takana_upgrade::boot_graph::BOOT_SELECT_PATH)] select: PathBuf, }, /// [ADR 0010 · HARNESS de dev/VM] Orquesta el menú de boot completo: emite el grafo, lanza el @@ -517,10 +517,10 @@ enum BootCmd { #[arg(long, default_value = "mirada-compositor --arranque")] compositor: String, /// Path donde publicar el grafo antes de lanzar el compositor. - #[arg(long, default_value = hammer_upgrade::boot_graph::BOOT_GRAPH_PATH)] + #[arg(long, default_value = takana_upgrade::boot_graph::BOOT_GRAPH_PATH)] out: PathBuf, /// Path del canal de vuelta donde el compositor deja el id elegido. - #[arg(long, default_value = hammer_upgrade::boot_graph::BOOT_SELECT_PATH)] + #[arg(long, default_value = takana_upgrade::boot_graph::BOOT_SELECT_PATH)] select: PathBuf, }, } @@ -744,15 +744,15 @@ enum BootstrapCmd { } /// Parsea la clase de semilla del flag `--seed`. Único punto de verdad para todas las subcomandos. -fn parse_seed_kind(s: &str) -> anyhow::Result { +fn parse_seed_kind(s: &str) -> anyhow::Result { match s { - "zig" => Ok(hammer_bootstrap::SeedKind::Zig), - "musl-cross-make" => Ok(hammer_bootstrap::SeedKind::MuslCrossMake), + "zig" => Ok(takana_bootstrap::SeedKind::Zig), + "musl-cross-make" => Ok(takana_bootstrap::SeedKind::MuslCrossMake), other => anyhow::bail!("--seed debe ser 'zig' o 'musl-cross-make', no '{other}'"), } } -fn print_event(ev: &hammer_journal::MutationEvent, format: &str) { +fn print_event(ev: &takana_journal::MutationEvent, format: &str) { match format { "json" => { // Re-serializa. No imprimimos la línea original (no la tenemos a mano), pero el @@ -764,12 +764,12 @@ fn print_event(ev: &hammer_journal::MutationEvent, format: &str) { } _ => { let actor = match &ev.by.source { - hammer_journal::Source::HammerHydrate { artifact } => format!("hydrate {artifact}"), - hammer_journal::Source::HammerCommit { overlay, artifact } => match artifact { + takana_journal::Source::HammerHydrate { artifact } => format!("hydrate {artifact}"), + takana_journal::Source::HammerCommit { overlay, artifact } => match artifact { Some(a) => format!("commit {overlay} ({a})"), None => format!("commit {overlay}"), }, - hammer_journal::Source::External => { + takana_journal::Source::External => { let pid = ev.by.pid.map(|p| format!("pid={p}")).unwrap_or_default(); let uid = ev.by.uid.map(|u| format!("uid={u}")).unwrap_or_default(); format!("external {pid} {uid}").trim().to_string() @@ -800,20 +800,20 @@ fn main() -> anyhow::Result<()> { // Las cmds de overlay/diario/apply pueden correr en sistemas sin store local todavía. match cli.cmd { Cmd::Build { recipe } => { - let store = hammer_core::Store::open(&cli.store)?; - let recipe = hammer_core::Recipe::load_from_path(&recipe)?; - let cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - let hash = hammer_build::build(&recipe, &cfg, &store)?; + let store = takana_core::Store::open(&cli.store)?; + let recipe = takana_core::Recipe::load_from_path(&recipe)?; + let cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + let hash = takana_build::build(&recipe, &cfg, &store)?; println!("{hash}"); } Cmd::Hash { recipe, check } => { - let store = hammer_core::Store::open(&cli.store)?; - let recipe = hammer_core::Recipe::load_from_path(&recipe)?; + let store = takana_core::Store::open(&cli.store)?; + let recipe = takana_core::Recipe::load_from_path(&recipe)?; // Misma resolución de lab que `build`, o `hash` mentiría: el toolchain entra en el // ArtifactHash, así que un `hash` que no lo mire daría una dirección que `build` no usa. - let cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - let lab = hammer_core::lab::LabFingerprint::from_rootfs(&cfg.rootfs)?; - let hash = hammer_build::artifact_hash(&recipe, &store, &lab)?; + let cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + let lab = takana_core::lab::LabFingerprint::from_rootfs(&cfg.rootfs)?; + let hash = takana_build::artifact_hash(&recipe, &store, &lab)?; if check { // ¿el artefacto VIGENTE (el que corresponde a la receta de HOY) ya está sellado? // Es lo que static-audit.sh no podía saber: `ls -dt store/*-` da el más RECIENTE, @@ -829,7 +829,7 @@ fn main() -> anyhow::Result<()> { } } Cmd::WhyDiffers { a, b, json } => { - let informe = hammer_core::why_differs(std::path::Path::new(&a), std::path::Path::new(&b))?; + let informe = takana_core::why_differs(std::path::Path::new(&a), std::path::Path::new(&b))?; if json { println!("{}", serde_json::to_string_pretty(&informe)?); } else { @@ -864,7 +864,7 @@ fn main() -> anyhow::Result<()> { } } Cmd::Attest { rootfs } => { - let report = hammer_bootstrap::verify_attestation(std::path::Path::new(&rootfs))?; + let report = takana_bootstrap::verify_attestation(std::path::Path::new(&rootfs))?; for p in &report.ok { println!(" ✓ {p}"); } @@ -888,14 +888,14 @@ fn main() -> anyhow::Result<()> { } } Cmd::Hydrate { hash, into, link } => { - let store = hammer_core::Store::open(&cli.store)?; + let store = takana_core::Store::open(&cli.store)?; let mode = match link.as_str() { - "static" => hammer_core::LinkMode::Static, - "dynamic" => hammer_core::LinkMode::Dynamic, + "static" => takana_core::LinkMode::Static, + "dynamic" => takana_core::LinkMode::Dynamic, other => anyhow::bail!("--link debe ser 'static' o 'dynamic', no '{other}'"), }; let artifact_dir = store.find_by_hash(&hash)?; - let report = hammer_build::run_hydrate( + let report = takana_build::run_hydrate( &artifact_dir, std::path::Path::new(&into), mode, @@ -914,20 +914,20 @@ fn main() -> anyhow::Result<()> { } Cmd::Try { targets, state_root } => { let root = state_root - .unwrap_or_else(|| PathBuf::from(hammer_overlay::DEFAULT_STATE_ROOT)); + .unwrap_or_else(|| PathBuf::from(takana_overlay::DEFAULT_STATE_ROOT)); std::fs::create_dir_all(&root)?; - let id = hammer_overlay::try_overlay(&targets, &root)?; + let id = takana_overlay::try_overlay(&targets, &root)?; println!("{id}"); } Cmd::Commit { id, state_root, journal, no_journal } => { let root = state_root - .unwrap_or_else(|| PathBuf::from(hammer_overlay::DEFAULT_STATE_ROOT)); - let id = hammer_overlay::OverlayId(id); + .unwrap_or_else(|| PathBuf::from(takana_overlay::DEFAULT_STATE_ROOT)); + let id = takana_overlay::OverlayId(id); let report = if no_journal { - hammer_overlay::commit(&id, &root)? + takana_overlay::commit(&id, &root)? } else { - let j = hammer_journal::Journal::open(&journal)?; - hammer_overlay::commit_with_journal(&id, &root, &j)? + let j = takana_journal::Journal::open(&journal)?; + takana_overlay::commit_with_journal(&id, &root, &j)? }; println!( "commit OK — {} archivo(s) promocionados, {} eliminado(s){}", @@ -938,14 +938,14 @@ fn main() -> anyhow::Result<()> { } Cmd::Discard { id, state_root } => { let root = state_root - .unwrap_or_else(|| PathBuf::from(hammer_overlay::DEFAULT_STATE_ROOT)); - hammer_overlay::discard(&hammer_overlay::OverlayId(id), &root)?; + .unwrap_or_else(|| PathBuf::from(takana_overlay::DEFAULT_STATE_ROOT)); + takana_overlay::discard(&takana_overlay::OverlayId(id), &root)?; println!("discard OK"); } Cmd::Status { state_root } => { let root = state_root - .unwrap_or_else(|| PathBuf::from(hammer_overlay::DEFAULT_STATE_ROOT)); - let overlays = hammer_overlay::status(&root)?; + .unwrap_or_else(|| PathBuf::from(takana_overlay::DEFAULT_STATE_ROOT)); + let overlays = takana_overlay::status(&root)?; if overlays.is_empty() { println!("(sin overlays activos)"); } else { @@ -963,7 +963,7 @@ fn main() -> anyhow::Result<()> { } } Cmd::Journal { dir, tail, follow, format } => { - let j = hammer_journal::Journal::open(&dir)?; + let j = takana_journal::Journal::open(&dir)?; let initial = j.tail(tail)?; for ev in &initial { print_event(ev, &format); @@ -1104,29 +1104,29 @@ fn main() -> anyhow::Result<()> { Cmd::Bootstrap { sub } => match sub { BootstrapCmd::Stage0 { url, sha256, version, seed } => { let kind = parse_seed_kind(&seed)?; - let store = hammer_core::Store::open(&cli.store)?; - let spec = hammer_bootstrap::SeedSpec { kind, version, url, sha256 }; - let hash = hammer_bootstrap::stage0(&spec, &store)?; + let store = takana_core::Store::open(&cli.store)?; + let spec = takana_bootstrap::SeedSpec { kind, version, url, sha256 }; + let hash = takana_bootstrap::stage0(&spec, &store)?; println!("{hash}"); } BootstrapCmd::Stage1 { seed_hash, seed, recipes } => { let seed_kind = parse_seed_kind(&seed)?; - let store = hammer_core::Store::open(&cli.store)?; - let base_cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - let spec = hammer_bootstrap::Stage1Spec { - seed_hash: hammer_core::ArtifactHash::from_hex(seed_hash.trim_start_matches("b3:")), + let store = takana_core::Store::open(&cli.store)?; + let base_cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + let spec = takana_bootstrap::Stage1Spec { + seed_hash: takana_core::ArtifactHash::from_hex(seed_hash.trim_start_matches("b3:")), seed_kind, recipes_dir: std::path::PathBuf::from(recipes), }; - let hash = hammer_bootstrap::stage1(&spec, &base_cfg, &store)?; + let hash = takana_bootstrap::stage1(&spec, &base_cfg, &store)?; println!("{hash}"); } BootstrapCmd::Product { rootfs, recipes, attest, policy, rootkey, from_repo, trust } => { - let store = hammer_core::Store::open(&cli.store)?; + let store = takana_core::Store::open(&cli.store)?; // El zig del lab (no la semilla): los servicios usan su `zig_version` propia // (openssh ⇒ 0.13.0, hermano del default), y si ya están sellados, salen cacheados. - let base_cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - let base = hammer_core::ArtifactHash::from_hex(rootfs.trim_start_matches("b3:")); + let base_cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + let base = takana_core::ArtifactHash::from_hex(rootfs.trim_start_matches("b3:")); let recipes_dir = std::path::Path::new(&recipes); let hash = if let Some(repo) = from_repo { // [Dogfood] userland desde el repo FIRMADO (la imagen arma su userland por la cadena @@ -1138,7 +1138,7 @@ fn main() -> anyhow::Result<()> { let trust_dir = trust.ok_or_else(|| { anyhow::anyhow!("--from-repo requiere --trust (verificar la firma del release)") })?; - hammer_bootstrap::product_from_repo( + takana_bootstrap::product_from_repo( &base, std::path::Path::new(&repo), std::path::Path::new(&trust_dir), @@ -1146,40 +1146,40 @@ fn main() -> anyhow::Result<()> { &store, )? } else if attest { - let mut cfg = hammer_bootstrap::AttestConfig { policy, ..Default::default() }; + let mut cfg = takana_bootstrap::AttestConfig { policy, ..Default::default() }; if let Some(path) = rootkey { let bytes = std::fs::read(&path)?; cfg.rootkey = bytes.as_slice().try_into().map_err(|_| { anyhow::anyhow!("la rootkey {path} debe ser exactamente 32 bytes (son {})", bytes.len()) })?; } - hammer_bootstrap::product_attested(&base, &base_cfg, recipes_dir, &store, &cfg)? + takana_bootstrap::product_attested(&base, &base_cfg, recipes_dir, &store, &cfg)? } else { - hammer_bootstrap::product(&base, &base_cfg, recipes_dir, &store)? + takana_bootstrap::product(&base, &base_cfg, recipes_dir, &store)? }; println!("{hash}"); } BootstrapCmd::Stage2 { rootfs, verify } => { - let store = hammer_core::Store::open(&cli.store)?; + let store = takana_core::Store::open(&cli.store)?; let rootfs_hash = - hammer_core::ArtifactHash::from_hex(rootfs.trim_start_matches("b3:")); - let report = hammer_bootstrap::stage2(&rootfs_hash, &store)?; + takana_core::ArtifactHash::from_hex(rootfs.trim_start_matches("b3:")); + let report = takana_bootstrap::stage2(&rootfs_hash, &store)?; println!("stage1 content-hash: {}", report.stage1_content); match verify { None => println!("referencia anclada (rebuild nativo de stage1': correr en la VM)"), Some(rebuilt) => { let rb = - hammer_core::ArtifactHash::from_hex(rebuilt.trim_start_matches("b3:")); - match hammer_bootstrap::verify_against(&report, rb) { - hammer_bootstrap::Reproducibility::Reproducible => { + takana_core::ArtifactHash::from_hex(rebuilt.trim_start_matches("b3:")); + match takana_bootstrap::verify_against(&report, rb) { + takana_bootstrap::Reproducibility::Reproducible => { println!("✓ REPRODUCIBLE: stage1' == stage1 (auto-alojado bit a bit)"); } - hammer_bootstrap::Reproducibility::Divergent { stage1, rebuilt } => { + takana_bootstrap::Reproducibility::Divergent { stage1, rebuilt } => { anyhow::bail!( "✗ DIVERGENTE: stage1={stage1} rebuilt={rebuilt} — hay no-determinismo que cazar (SDD 09 §2)" ); } - hammer_bootstrap::Reproducibility::RebuildPending => unreachable!(), + takana_bootstrap::Reproducibility::RebuildPending => unreachable!(), } } } @@ -1198,23 +1198,23 @@ fn main() -> anyhow::Result<()> { out, } => { let seed_kind = parse_seed_kind(&seed)?; - let store = hammer_core::Store::open(&cli.store)?; + let store = takana_core::Store::open(&cli.store)?; let swaps = swaps.iter().map(|s| parse_swap(s)).collect::>>()?; - let spec = hammer_bootstrap::BuilderSpec { - stage1_rootfs: hammer_core::ArtifactHash::from_hex(stage1.trim_start_matches("b3:")), - seed_hash: hammer_core::ArtifactHash::from_hex(seed_hash.trim_start_matches("b3:")), + let spec = takana_bootstrap::BuilderSpec { + stage1_rootfs: takana_core::ArtifactHash::from_hex(stage1.trim_start_matches("b3:")), + seed_hash: takana_core::ArtifactHash::from_hex(seed_hash.trim_start_matches("b3:")), seed_kind, recipes_dir: std::path::PathBuf::from(recipes), hammer_bin: std::path::PathBuf::from(hammer_bin), toolchain_src: std::path::PathBuf::from(toolchain), toolchain_tag, ref_content: ref_content - .map(|h| hammer_core::ArtifactHash::from_hex(h.trim_start_matches("b3:").to_string())), + .map(|h| takana_core::ArtifactHash::from_hex(h.trim_start_matches("b3:").to_string())), work_cache: work_cache.map(std::path::PathBuf::from), swaps, }; let out = std::path::PathBuf::from(out); - let report = hammer_bootstrap::builder_rootfs(&spec, &store, &out)?; + let report = takana_bootstrap::builder_rootfs(&spec, &store, &out)?; println!("builder rootfs: {}", report.builder_hash); println!("ensamblado en: {}", report.out_dir.display()); println!( @@ -1223,10 +1223,10 @@ fn main() -> anyhow::Result<()> { } BootstrapCmd::All { url, sha256, version, seed, recipes } => { let kind = parse_seed_kind(&seed)?; - let store = hammer_core::Store::open(&cli.store)?; - let base_cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - let spec = hammer_bootstrap::SeedSpec { kind, version, url, sha256 }; - let report = hammer_bootstrap::all( + let store = takana_core::Store::open(&cli.store)?; + let base_cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + let spec = takana_bootstrap::SeedSpec { kind, version, url, sha256 }; + let report = takana_bootstrap::all( &spec, std::path::Path::new(&recipes), &base_cfg, @@ -1248,8 +1248,8 @@ fn main() -> anyhow::Result<()> { ); } BootstrapCmd::Manifest => { - let store = hammer_core::Store::open(&cli.store)?; - let manifest = hammer_bootstrap::BootstrapManifest::load(&store)?; + let store = takana_core::Store::open(&cli.store)?; + let manifest = takana_bootstrap::BootstrapManifest::load(&store)?; println!("{}", serde_json::to_string_pretty(&manifest)?); } }, @@ -1258,7 +1258,7 @@ fn main() -> anyhow::Result<()> { match sub { MirrorCmd::Push { remote } => { let remote = std::path::PathBuf::from(&remote); - let r = hammer_mirror::sync(&local, &remote)?; + let r = takana_mirror::sync(&local, &remote)?; print_sync("push", &r); if !r.ok() { anyhow::bail!("mirror push incompleto: {} fallo(s), {} conflicto(s)", r.failed.len(), r.conflicts.len()); @@ -1266,7 +1266,7 @@ fn main() -> anyhow::Result<()> { } MirrorCmd::Pull { remote } => { let remote = std::path::PathBuf::from(&remote); - let r = hammer_mirror::sync(&remote, &local)?; + let r = takana_mirror::sync(&remote, &local)?; print_sync("pull", &r); if !r.ok() { anyhow::bail!("mirror pull incompleto: {} fallo(s), {} conflicto(s)", r.failed.len(), r.conflicts.len()); @@ -1274,7 +1274,7 @@ fn main() -> anyhow::Result<()> { } MirrorCmd::Status { remote } => { let remote = std::path::PathBuf::from(&remote); - let (missing_remote, missing_local, conflicts) = hammer_mirror::diff(&local, &remote)?; + let (missing_remote, missing_local, conflicts) = takana_mirror::diff(&local, &remote)?; println!("faltan en el remoto (push los lleva): {}", missing_remote.len()); for a in &missing_remote { println!(" → {}", a.dir); } println!("faltan en el local (pull los trae): {}", missing_local.len()); @@ -1290,8 +1290,8 @@ fn main() -> anyhow::Result<()> { let state_root = std::path::PathBuf::from(&state_root); match sub { UpgradeCmd::Apply { tree_dir, expected } => { - let j = hammer_journal::Journal::open(&journal)?; - let r = hammer_upgrade::apply( + let j = takana_journal::Journal::open(&journal)?; + let r = takana_upgrade::apply( &store, &tree_dir, expected.as_deref(), &root, &state_root, Some(&j), )?; if r.already_current { @@ -1303,8 +1303,8 @@ fn main() -> anyhow::Result<()> { } } UpgradeCmd::Rollback => { - let j = hammer_journal::Journal::open(&journal)?; - let r = hammer_upgrade::rollback(&root, &state_root, Some(&j))?; + let j = takana_journal::Journal::open(&journal)?; + let r = takana_upgrade::rollback(&root, &state_root, Some(&j))?; println!("✓ generación {} revertida", r.reverted); match r.now_current { Some(id) => println!(" ahora viva: generación {id}"), @@ -1313,8 +1313,8 @@ fn main() -> anyhow::Result<()> { println!(" {} restaurados, {} borrados", r.restored.len(), r.deleted.len()); } UpgradeCmd::Recover { rollback } => { - let j = hammer_journal::Journal::open(&journal)?; - let r = hammer_upgrade::recover(&store, &root, &state_root, Some(&j), rollback)?; + let j = takana_journal::Journal::open(&journal)?; + let r = takana_upgrade::recover(&store, &root, &state_root, Some(&j), rollback)?; if !r.recovered { println!("no hay apply interrumpido — nada que recuperar"); } else if r.rolled_forward { @@ -1324,15 +1324,15 @@ fn main() -> anyhow::Result<()> { } } UpgradeCmd::Status => { - if let Some(p) = hammer_upgrade::pending(&state_root)? { + if let Some(p) = takana_upgrade::pending(&state_root)? { println!("⚠ apply interrumpido pendiente (generación {}) — corré `hammer upgrade recover [--rollback]`", p.id); } - let cur = hammer_upgrade::current(&state_root)?; + let cur = takana_upgrade::current(&state_root)?; match cur { Some(id) => println!("generación viva: {id}"), None => println!("generación viva: (ninguna — sistema sin upgrades aplicados)"), } - let gens = hammer_upgrade::list(&state_root)?; + let gens = takana_upgrade::list(&state_root)?; println!("historial: {} generación(es)", gens.len()); for g in &gens { let mark = if Some(g.id) == cur { "*" } else { " " }; @@ -1340,14 +1340,14 @@ fn main() -> anyhow::Result<()> { } } UpgradeCmd::Prune { keep } => { - let r = hammer_upgrade::prune(&state_root, keep)?; + let r = takana_upgrade::prune(&state_root, keep)?; println!("✓ prune: {} borradas, {} conservadas", r.removed.len(), r.kept.len()); for id in &r.removed { println!(" - {id}"); } } } } Cmd::Boot { root, state_root, journal, sub } => { - use hammer_upgrade::boot_graph; + use takana_upgrade::boot_graph; let root = std::path::PathBuf::from(&root); let state_root = std::path::PathBuf::from(&state_root); match sub { @@ -1390,7 +1390,7 @@ fn main() -> anyhow::Result<()> { "pasá un o usá --from-select para leerlo de {}", select.display()), }; - let j = hammer_journal::Journal::open(&journal)?; + let j = takana_journal::Journal::open(&journal)?; let graph_out = std::path::PathBuf::from(boot_graph::BOOT_GRAPH_PATH); activate_and_report(&root, &state_root, &j, &id, &graph_out)?; // La selección ya se aplicó: consumir el canal para que una segunda corrida @@ -1436,7 +1436,7 @@ fn main() -> anyhow::Result<()> { match sel { None => println!("hammer boot menu: sin selección — arranque normal"), Some(id) => { - let j = hammer_journal::Journal::open(&journal)?; + let j = takana_journal::Journal::open(&journal)?; activate_and_report(&root, &state_root, &j, &id, &out)?; } } @@ -1454,11 +1454,11 @@ fn main() -> anyhow::Result<()> { fn activate_and_report( root: &std::path::Path, state_root: &std::path::Path, - journal: &hammer_journal::Journal, + journal: &takana_journal::Journal, id: &str, graph_out: &std::path::Path, ) -> anyhow::Result<()> { - use hammer_upgrade::boot_graph; + use takana_upgrade::boot_graph; let r = boot_graph::activate(root, state_root, Some(journal), id)?; if r.already_current { println!("✓ nodo {} ya era el vivo — no-op", r.target); @@ -1474,7 +1474,7 @@ fn activate_and_report( } /// Imprime el reporte de un `mirror push|pull`. -fn print_sync(verbo: &str, r: &hammer_mirror::SyncReport) { +fn print_sync(verbo: &str, r: &takana_mirror::SyncReport) { for d in &r.copied { println!(" ✓ {d}"); } @@ -1494,29 +1494,29 @@ fn print_sync(verbo: &str, r: &hammer_mirror::SyncReport) { } /// Lee y deserializa un `.swm` desde disco; falla con mensaje útil si no parsea. -fn load_swm(file: &str) -> anyhow::Result { +fn load_swm(file: &str) -> anyhow::Result { let yaml = std::fs::read_to_string(file) .map_err(|e| anyhow::anyhow!("no pude leer {file}: {e}"))?; - hammer_core::Swm::from_yaml(&yaml) + takana_core::Swm::from_yaml(&yaml) .map_err(|e| anyhow::anyhow!("no pude parsear {file}: {e}")) } /// Lee una `BaseRef` local desde JSON; usada por `apply` y `swm verify` para verificar la /// compatibilidad de pins. Si la ruta no existe, devuelve `Ok(None)` para que el caller /// pueda decidir entre fallar o seguir con un warning. -fn load_local_base(path: Option<&std::path::Path>) -> anyhow::Result> { +fn load_local_base(path: Option<&std::path::Path>) -> anyhow::Result> { let Some(p) = path else { return Ok(None) }; if !p.is_file() { return Err(anyhow::anyhow!("base-ref {} no existe", p.display())); } let bytes = std::fs::read(p)?; - let base: hammer_core::BaseRef = + let base: takana_core::BaseRef = serde_json::from_slice(&bytes).map_err(|e| anyhow::anyhow!("base-ref inválido: {e}"))?; Ok(Some(base)) } -fn print_base_compat(c: &hammer_core::BaseCompat) { - use hammer_core::BaseCompat::*; +fn print_base_compat(c: &takana_core::BaseCompat) { + use takana_core::BaseCompat::*; match c { Ok => eprintln!("verify_base: OK"), DistroMismatch { local, swm } => eprintln!( @@ -1545,8 +1545,8 @@ fn run_swm_verify( println!("schema: OK ({} mutación(es))", swm.mutations.len()); // Verificación de hash de los file_drop inline (no toca disco). for (i, m) in swm.mutations.iter().enumerate() { - if let hammer_core::Mutation::FileDrop { content_b64: Some(b64), content_hash, path, .. } = m { - hammer_core::apply::verify_content_hash(b64, content_hash).map_err(|e| { + if let takana_core::Mutation::FileDrop { content_b64: Some(b64), content_hash, path, .. } = m { + takana_core::apply::verify_content_hash(b64, content_hash).map_err(|e| { anyhow::anyhow!("file_drop #{} en {path}: {e}", i + 1) })?; } @@ -1569,38 +1569,38 @@ fn run_swm_verify( /// "reproduce + estas N pruebas pasan" antes de que el humano proponga (SDD 15 §H1). Frontera: /// paquetes con build-deps necesitan esas recetas resolubles en el catálogo del lab (como `install`); /// para el caso self-contained (binario estático sin deps) alcanza con el `.swm`. -fn run_swm_evidence(swm: &hammer_core::Swm, store_path: &std::path::Path) -> anyhow::Result<()> { +fn run_swm_evidence(swm: &takana_core::Swm, store_path: &std::path::Path) -> anyhow::Result<()> { // Corto-circuito ANTES de tocar el store/catálogo: si ninguna mutación trae evidencia, no hay // nada que reproducir (y no forzamos abrir un store que quizá no exista/no sea escribible). let has_evidence = swm.mutations.iter().any(|m| { - matches!(m, hammer_core::Mutation::SourcePatch { evidence, .. } if !evidence.is_empty()) + matches!(m, takana_core::Mutation::SourcePatch { evidence, .. } if !evidence.is_empty()) }); if !has_evidence { println!("evidence: ninguna mutación declara evidencia (nada que verificar)"); return Ok(()); } - let store = hammer_core::Store::open(store_path)?; - let cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - let catalog_dir = hammer_build::swm_bridge::catalog_dir_for(&cfg, None); + let store = takana_core::Store::open(store_path)?; + let cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + let catalog_dir = takana_build::swm_bridge::catalog_dir_for(&cfg, None); std::fs::create_dir_all(&catalog_dir)?; let mut ran = 0usize; let mut failed = 0usize; for m in &swm.mutations { - let hammer_core::Mutation::SourcePatch { evidence, target_bin, .. } = m else { + let takana_core::Mutation::SourcePatch { evidence, target_bin, .. } = m else { continue; }; if evidence.is_empty() { continue; } let recipe = - hammer_build::swm_bridge::recipe_from_source_patch(m, None, &catalog_dir)?; + takana_build::swm_bridge::recipe_from_source_patch(m, None, &catalog_dir)?; println!( "evidence: reproduciendo {target_bin} y corriendo {} check(s)…", evidence.checks.len() ); - let report = hammer_build::run_evidence(&recipe, &cfg, &store)?; + let report = takana_build::run_evidence(&recipe, &cfg, &store)?; for r in &report.results { let mark = if r.outcome.passed { "✓" } else { "✗" }; println!( @@ -1636,27 +1636,27 @@ const DEFAULT_TRUST_DIR: &str = "/var/lib/hammer/trust"; /// informa autoría/integridad; NO autoriza promover (eso lo decide la reproducción + commit /// humano). Ver `docs/09-trust-model.md`. fn print_sig_status( - swm: &hammer_core::Swm, + swm: &takana_core::Swm, trust: Option<&std::path::Path>, ) -> anyhow::Result<()> { let trust_dir = trust.unwrap_or_else(|| std::path::Path::new(DEFAULT_TRUST_DIR)); - let store = hammer_core::TrustStore::load(trust_dir)?; + let store = takana_core::TrustStore::load(trust_dir)?; let status = swm.verify_signature(&store); match &status { - hammer_core::SigStatus::Trusted { by } => { + takana_core::SigStatus::Trusted { by } => { println!("firma: trusted (by {by})"); } - hammer_core::SigStatus::UnknownKey { by } => { + takana_core::SigStatus::UnknownKey { by } => { println!( "firma: unknown-key (by {by}) — añade su clave a {} para confiar en la autoría", trust_dir.display() ); } - hammer_core::SigStatus::BadSig { by, reason } => { + takana_core::SigStatus::BadSig { by, reason } => { eprintln!("firma: BAD-SIG (by {by}): {reason}"); anyhow::bail!("la firma del .swm no valida"); } - hammer_core::SigStatus::Unsigned => { + takana_core::SigStatus::Unsigned => { println!("firma: unsigned"); } } @@ -1665,7 +1665,7 @@ fn print_sig_status( fn run_keygen(name: &str, out: Option<&std::path::Path>) -> anyhow::Result<()> { let dir = out.unwrap_or_else(|| std::path::Path::new(DEFAULT_TRUST_DIR)); - let kp = hammer_core::KeyPair::generate()?; + let kp = takana_core::KeyPair::generate()?; let pub_path = kp.write_to(dir, name)?; println!("clave pública: {}", pub_path.display()); println!("clave privada: {} (modo 0600 — guárdala)", dir.join(format!("{name}.ed25519")).display()); @@ -1688,7 +1688,7 @@ fn run_pack( sign: Option<&std::path::Path>, store_path: &str, ) -> anyhow::Result<()> { - let recipe = hammer_core::Recipe::load_from_path(recipe_path) + let recipe = takana_core::Recipe::load_from_path(recipe_path) .map_err(|e| anyhow::anyhow!("no pude cargar la receta {}: {e}", recipe_path.display()))?; // Las deps por NOMBRE viajan en el `source_patch` y en el índice; `install` resuelve el cierre @@ -1745,9 +1745,9 @@ fn run_pack( let expected_hash: Option = if let Some(h) = expected { Some(h.to_string()) } else if do_build { - let store = hammer_core::Store::open(store_path)?; - let cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - let hash = hammer_build::build(&recipe, &cfg, &store) + let store = takana_core::Store::open(store_path)?; + let cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + let hash = takana_build::build(&recipe, &cfg, &store) .map_err(|e| anyhow::anyhow!("construyendo la receta para sellar expected_hash: {e}"))?; eprintln!("construida: {hash}"); Some(hash.as_str().to_string()) @@ -1755,7 +1755,7 @@ fn run_pack( None }; - let mut swm = hammer_core::Swm::from_recipe( + let mut swm = takana_core::Swm::from_recipe( &recipe, target_bin, patch_text, @@ -1766,7 +1766,7 @@ fn run_pack( if let Some(key) = sign { let priv_b64 = std::fs::read_to_string(key) .map_err(|e| anyhow::anyhow!("no pude leer la clave {}: {e}", key.display()))?; - let kp = hammer_core::KeyPair::from_private_b64(&priv_b64)?; + let kp = takana_core::KeyPair::from_private_b64(&priv_b64)?; let by = key .file_name() .map(|f| f.to_string_lossy().trim_end_matches(".ed25519").to_string()) @@ -1800,8 +1800,8 @@ fn run_pack( let file_name = format!("{}-{}.tkn", recipe.name, recipe.version); std::fs::create_dir_all(repo_dir)?; std::fs::write(repo_dir.join(&file_name), &yaml)?; - let mut index = hammer_core::RepoIndex::load(repo_dir)?; - let orphan = index.upsert(hammer_core::PackageEntry { + let mut index = takana_core::RepoIndex::load(repo_dir)?; + let orphan = index.upsert(takana_core::PackageEntry { name: recipe.name.clone(), version: recipe.version.clone(), file: file_name, @@ -1809,7 +1809,7 @@ fn run_pack( expected_hash: expected_hash.clone(), // El digest se sella al publicar y lo cubre la firma del índice: es lo que permite // servir los `.swm` desde espejos que no controlamos (ADR 0014). - digest: Some(hammer_core::repo::digest_swm(yaml.as_bytes())), + digest: Some(takana_core::repo::digest_swm(yaml.as_bytes())), signed_by: swm.signature.as_ref().map(|s| s.by.clone()), deps: recipe.deps.build.clone(), }); @@ -1882,7 +1882,7 @@ impl RepoSource { ) -> anyhow::Result<(Vec, &'a str)> { let mut ultimo = None; for base in bases { - match hammer_build::download::fetch_url_bytes(&format!("{base}/{rel}")) { + match takana_build::download::fetch_url_bytes(&format!("{base}/{rel}")) { Ok(bytes) => return Ok((bytes, base.as_str())), Err(e) => ultimo = Some(e), } @@ -1898,12 +1898,12 @@ impl RepoSource { } /// Lee el índice del repo (local: `index.json`; http: `GET /index.json`). - fn read_index(&self) -> anyhow::Result { + fn read_index(&self) -> anyhow::Result { match self { - RepoSource::Local(d) => Ok(hammer_core::RepoIndex::load(d)?), + RepoSource::Local(d) => Ok(takana_core::RepoIndex::load(d)?), RepoSource::Http(bases) => { let (bytes, origen) = - Self::fetch_desde_algun_origen(bases, hammer_core::repo::INDEX_FILE)?; + Self::fetch_desde_algun_origen(bases, takana_core::repo::INDEX_FILE)?; serde_json::from_slice(&bytes) .map_err(|e| anyhow::anyhow!("índice remoto de {origen}: {e}")) } @@ -1919,7 +1919,7 @@ impl RepoSource { /// N espejos podría servir otro manifiesto bajo el mismo nombre de fichero. fn materialize( &self, - index: &hammer_core::RepoIndex, + index: &takana_core::RepoIndex, files: &[&str], tmp_holder: &mut Option, ) -> anyhow::Result { @@ -1942,7 +1942,7 @@ impl RepoSource { // fallback aquí convertiría una manipulación en silencio: el paquete acabaría // instalándose desde el espejo bueno y nadie se enteraría de que uno miente. // Ausencia (404, host caído) sí es motivo para seguir; contenido distinto no. - hammer_core::repo::verify_digest(entry, &bytes)?; + takana_core::repo::verify_digest(entry, &bytes)?; if entry.digest.is_none() { sin_digest += 1; } @@ -1999,19 +1999,19 @@ fn run_install( // se valida la autoría. Esto es ortogonal a la firma de cada `.swm`. { let trust_dir = trust.unwrap_or_else(|| std::path::Path::new(DEFAULT_TRUST_DIR)); - let store = hammer_core::TrustStore::load(trust_dir)?; + let store = takana_core::TrustStore::load(trust_dir)?; match index.verify_signature(&store) { - hammer_core::SigStatus::Trusted { by } => eprintln!("release: trusted (by {by})"), - hammer_core::SigStatus::UnknownKey { by } => { + takana_core::SigStatus::Trusted { by } => eprintln!("release: trusted (by {by})"), + takana_core::SigStatus::UnknownKey { by } => { eprintln!("release: unknown-key (by {by}) — autoría del catálogo no confiada"); if require_signed { anyhow::bail!("--require-signed: el release está firmado por '{by}', clave no confiada en {}", trust_dir.display()); } } - hammer_core::SigStatus::BadSig { by, reason } => { + takana_core::SigStatus::BadSig { by, reason } => { anyhow::bail!("release: BAD-SIG (by {by}): {reason} — el índice fue manipulado") } - hammer_core::SigStatus::Unsigned => { + takana_core::SigStatus::Unsigned => { eprintln!("release: sin firmar"); if require_signed { anyhow::bail!("--require-signed: el repo no tiene firma de release (firmalo con `hammer repo sign`)"); @@ -2038,7 +2038,7 @@ fn run_install( let repo_dir = source.materialize(&index, &needed, &mut _tmp_repo)?; let repo_dir = repo_dir.as_path(); - let swm_path = hammer_core::RepoIndex::swm_path(repo_dir, entry); + let swm_path = takana_core::RepoIndex::swm_path(repo_dir, entry); eprintln!( "install {} {} ← {}", entry.name, @@ -2067,9 +2067,9 @@ fn run_install( // autor prometa `slots`). Si alguno lo posee OTRO paquete instalado, es una colisión de fichero // (elección, no error) — salvo --force-slots. Se conoce antes de hidratar ⇒ aborta sin tocar nada. { - let idb = hammer_core::InstalledDb::load(db_path)?; - let paths = hammer_core::compat::output_paths(&entrant_swm); - let cols = hammer_core::compat::path_collisions(&idb, name, &paths); + let idb = takana_core::InstalledDb::load(db_path)?; + let paths = takana_core::compat::output_paths(&entrant_swm); + let cols = takana_core::compat::path_collisions(&idb, name, &paths); if !cols.is_empty() { let detalle = cols .iter() @@ -2091,9 +2091,9 @@ fn run_install( // que hay en el repo (contra la que el paquete se construyó). Si la tengo instalada a OTRO // hash, la diverguí ⇒ rechazo duro (el caso wayland, derivado — no lo salva --force-slots). { - let idb = hammer_core::InstalledDb::load(db_path)?; - let req = hammer_core::compat::observed_requires(&entrant_swm, &index); - let conflicts = hammer_core::compat::version_conflicts(&idb, &req); + let idb = takana_core::InstalledDb::load(db_path)?; + let req = takana_core::compat::observed_requires(&entrant_swm, &index); + let conflicts = takana_core::compat::version_conflicts(&idb, &req); if !conflicts.is_empty() { let d = conflicts .iter() @@ -2113,10 +2113,10 @@ fn run_install( entrant_slots .validate() .map_err(|e| anyhow::anyhow!("slots del paquete inválidos: {e}"))?; - let idb = hammer_core::InstalledDb::load(db_path)?; + let idb = takana_core::InstalledDb::load(db_path)?; let estado = idb.system_state(); - match hammer_core::compat::evaluar(&estado, &entrant_slots) { - hammer_core::CompatVeredicto::Compatible => { + match takana_core::compat::evaluar(&estado, &entrant_slots) { + takana_core::CompatVeredicto::Compatible => { eprintln!( "compat: compatible ({} reclamo(s), {} requisito(s) resuelto(s))", entrant_slots.claims.len(), @@ -2124,7 +2124,7 @@ fn run_install( ); } // Caso wayland: una dependencia sobre una superficie que el usuario divergió. Rechazo duro. - hammer_core::CompatVeredicto::Incompatible { slot, requerido, presente } => { + takana_core::CompatVeredicto::Incompatible { slot, requerido, presente } => { anyhow::bail!( "compat: INCOMPATIBLE — '{name}' requiere la superficie '{slot}' @ {requerido}, \ pero el sistema tiene {}. Divergiste esa superficie: no se instala sobre ella.", @@ -2132,7 +2132,7 @@ fn run_install( ); } // Caso logo: dos configs escriben la misma superficie. Es una ELECCIÓN, no un error. - hammer_core::CompatVeredicto::Colision { slot, instalado, entrante } => { + takana_core::CompatVeredicto::Colision { slot, instalado, entrante } => { if force_slots { eprintln!( "compat: colisión en '{slot}' ({instalado} → {entrante}); --force-slots ⇒ me quedo con la nueva" @@ -2152,15 +2152,15 @@ fn run_install( // el `source_patch`. Sin esto, un paquete con build-deps (openssh→zlib,openssl) no podría // reconstruirse: el sandbox no tendría headers/libs de las deps. if !entry.deps.is_empty() && !skip_source_patch { - let store = hammer_core::Store::open(store_path)?; - let cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - let catalog_dir = hammer_build::swm_bridge::catalog_dir_for(&cfg, None); + let store = takana_core::Store::open(store_path)?; + let cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + let catalog_dir = takana_build::swm_bridge::catalog_dir_for(&cfg, None); std::fs::create_dir_all(&catalog_dir)?; // El cierre incluye al propio target al final; el catálogo sólo necesita las DEPS (las // que el target y sus deps resolverán por nombre). Escribimos un `{dep}.toml` por cada una. let closure = index.resolve_closure(name)?; - let dep_pkgs: Vec<&hammer_core::PackageEntry> = + let dep_pkgs: Vec<&takana_core::PackageEntry> = closure.into_iter().filter(|p| p.name != name).collect(); if !dep_pkgs.is_empty() { eprintln!( @@ -2170,7 +2170,7 @@ fn run_install( ); } for dep in dep_pkgs { - let dep_swm_path = hammer_core::RepoIndex::swm_path(repo_dir, dep); + let dep_swm_path = takana_core::RepoIndex::swm_path(repo_dir, dep); let dep_swm = load_swm( dep_swm_path .to_str() @@ -2181,7 +2181,7 @@ fn run_install( })?; // El nombre de la receta DEBE ser el nombre del paquete: así el dependiente la // resuelve como `{dep}.toml`. - let dep_recipe = hammer_build::swm_bridge::recipe_from_source_patch( + let dep_recipe = takana_build::swm_bridge::recipe_from_source_patch( mutation, Some(&dep.name), &catalog_dir, @@ -2210,10 +2210,10 @@ fn run_install( // Registrar en la DB de instalados (salvo dry-run de schema). Permite `hammer uninstall`. if !skip_source_patch { - let mut idb = hammer_core::InstalledDb::load(db_path)?; + let mut idb = takana_core::InstalledDb::load(db_path)?; let files: Vec = created.iter().map(|p| p.to_string_lossy().into_owned()).collect(); let nfiles = files.len(); - idb.record(hammer_core::InstalledPackage { + idb.record(takana_core::InstalledPackage { name: pkg_name.clone(), version: pkg_version, hash: pkg_hash, @@ -2243,7 +2243,7 @@ fn run_import_nix(file: &str, out: Option<&std::path::Path>) -> anyhow::Result<( .map_err(|e| anyhow::anyhow!("JSON normalizado de nix inválido: {e}"))?; let toml = nix_import::to_recipe_toml(&pkg).map_err(|e| anyhow::anyhow!(e))?; // Sanity: la receta emitida debe parsear como Recipe de hammer. - hammer_core::Recipe::from_toml(&toml) + takana_core::Recipe::from_toml(&toml) .map_err(|e| anyhow::anyhow!("la receta importada no parsea (bug del importador): {e}"))?; match out { Some(dest) => { @@ -2295,18 +2295,18 @@ fn resolve_git_sha(repo: &str, tag: &str) -> anyhow::Result { fn run_pin(recipe_path: &std::path::Path, out: Option<&std::path::Path>) -> anyhow::Result<()> { let text = std::fs::read_to_string(recipe_path) .map_err(|e| anyhow::anyhow!("leyendo {}: {e}", recipe_path.display()))?; - let recipe = hammer_core::Recipe::from_toml(&text) + let recipe = takana_core::Recipe::from_toml(&text) .map_err(|e| anyhow::anyhow!("{}: {e}", recipe_path.display()))?; let (repo, commit) = match recipe.source.kind() { - Ok(hammer_core::SourceKind::Git { repo, commit }) => (repo.to_string(), commit.to_string()), - Ok(hammer_core::SourceKind::Tarball { .. }) => { + Ok(takana_core::SourceKind::Git { repo, commit }) => (repo.to_string(), commit.to_string()), + Ok(takana_core::SourceKind::Tarball { .. }) => { eprintln!("{}: tarball (ya anclado por sha256) — nada que pinear", recipe.name); return Ok(()); } // Una receta derivada ya está anclada por el CONTENIDO de su árbol (el hash entra en // `hash_inputs` calculado, no declarado) ⇒ no hay ref flotante que fijar. - Ok(hammer_core::SourceKind::Dir { dir }) => { + Ok(takana_core::SourceKind::Dir { dir }) => { eprintln!("{}: source.dir ({dir}) — anclado por contenido, nada que pinear", recipe.name); return Ok(()); } @@ -2353,7 +2353,7 @@ fn run_import_alpine(file: &str, out: Option<&std::path::Path>) -> anyhow::Resul std::fs::read_to_string(file).map_err(|e| anyhow::anyhow!("leyendo {file}: {e}"))? }; let toml = alpine_import::recipe_from_apkbuild(&text).map_err(|e| anyhow::anyhow!(e))?; - hammer_core::Recipe::from_toml(&toml) + takana_core::Recipe::from_toml(&toml) .map_err(|e| anyhow::anyhow!("la receta importada no parsea (bug del importador): {e}"))?; match out { Some(dest) => { @@ -2367,7 +2367,7 @@ fn run_import_alpine(file: &str, out: Option<&std::path::Path>) -> anyhow::Resul /// Lista los paquetes instalados de la DB. fn run_installed_list(db_path: &std::path::Path) -> anyhow::Result<()> { - let idb = hammer_core::InstalledDb::load(db_path)?; + let idb = takana_core::InstalledDb::load(db_path)?; if idb.packages.is_empty() { println!("nada instalado (DB {})", db_path.display()); return Ok(()); @@ -2387,7 +2387,7 @@ fn run_installed_list(db_path: &std::path::Path) -> anyhow::Result<()> { fn run_compat(repo: &str, db_path: &std::path::Path) -> anyhow::Result<()> { let source = RepoSource::parse(repo); let index = source.read_index()?; - let idb = hammer_core::InstalledDb::load(db_path)?; + let idb = takana_core::InstalledDb::load(db_path)?; let estado = idb.system_state(); // Materializamos TODOS los `.swm` (para HTTP los baja; para local es el propio dir). @@ -2397,7 +2397,7 @@ fn run_compat(repo: &str, db_path: &std::path::Path) -> anyhow::Result<()> { let (mut compatibles, mut elegibles, mut incompatibles) = (Vec::new(), Vec::new(), Vec::new()); for entry in &index.packages { - let swm_path = hammer_core::RepoIndex::swm_path(&repo_dir, entry); + let swm_path = takana_core::RepoIndex::swm_path(&repo_dir, entry); let swm = match swm_path.to_str().map(load_swm) { Some(Ok(s)) => s, _ => { @@ -2406,8 +2406,8 @@ fn run_compat(repo: &str, db_path: &std::path::Path) -> anyhow::Result<()> { } }; // 1a) Vía OBSERVADA de requisitos (H4e): una dep de runtime divergida ⇒ incompatible. - let req = hammer_core::compat::observed_requires(&swm, &index); - let vconf = hammer_core::compat::version_conflicts(&idb, &req); + let req = takana_core::compat::observed_requires(&swm, &index); + let vconf = takana_core::compat::version_conflicts(&idb, &req); if !vconf.is_empty() { let d = vconf.iter().map(|c| format!("{}@{} (tenés {})", c.dep, c.requerido, c.instalado)).collect::>().join(", "); incompatibles.push(format!("{:<16} deps divergidas: {d}", entry.name)); @@ -2415,8 +2415,8 @@ fn run_compat(repo: &str, db_path: &std::path::Path) -> anyhow::Result<()> { } // 1b) Vía DECLARADA (slots): una incompatibilidad domina todo. let slots = source_patch_slots(&swm); - let veredicto = hammer_core::compat::evaluar(&estado, &slots); - if let hammer_core::CompatVeredicto::Incompatible { slot, requerido, presente } = &veredicto { + let veredicto = takana_core::compat::evaluar(&estado, &slots); + if let takana_core::CompatVeredicto::Incompatible { slot, requerido, presente } = &veredicto { incompatibles.push(format!( "{:<16} requiere '{slot}' @ {requerido}, hay {}", entry.name, @@ -2425,9 +2425,9 @@ fn run_compat(repo: &str, db_path: &std::path::Path) -> anyhow::Result<()> { continue; } // 2) Colisión: de slot declarado (H4b) o de fichero observado (H4c) ⇒ requiere elección. - let paths = hammer_core::compat::output_paths(&swm); - let pcols = hammer_core::compat::path_collisions(&idb, &entry.name, &paths); - if let hammer_core::CompatVeredicto::Colision { slot, entrante, .. } = &veredicto { + let paths = takana_core::compat::output_paths(&swm); + let pcols = takana_core::compat::path_collisions(&idb, &entry.name, &paths); + if let takana_core::CompatVeredicto::Colision { slot, entrante, .. } = &veredicto { elegibles.push(format!("{:<16} colisión de slot '{slot}' (quiere {entrante})", entry.name)); } else if !pcols.is_empty() { let d = pcols.iter().map(|c| format!("{} (de '{}')", c.path, c.propietario)).collect::>().join(", "); @@ -2462,7 +2462,7 @@ fn run_compat(repo: &str, db_path: &std::path::Path) -> anyhow::Result<()> { /// también aporta — refcount) y quita su entrada de la DB. NO deshace `config_edit` (modifican /// ficheros ajenos, no creados por el paquete). fn run_uninstall(name: &str, db_path: &std::path::Path) -> anyhow::Result<()> { - let mut idb = hammer_core::InstalledDb::load(db_path)?; + let mut idb = takana_core::InstalledDb::load(db_path)?; let Some(pkg) = idb.find(name).cloned() else { let avail: Vec<&str> = idb.packages.iter().map(|p| p.name.as_str()).collect(); anyhow::bail!( @@ -2520,18 +2520,18 @@ fn run_uninstall(name: &str, db_path: &std::path::Path) -> anyhow::Result<()> { } /// Devuelve la primera mutación `source_patch` de un `.swm` empaquetado (el caso de `pack`). -fn source_patch_of(swm: &hammer_core::Swm) -> Option<&hammer_core::Mutation> { +fn source_patch_of(swm: &takana_core::Swm) -> Option<&takana_core::Mutation> { swm.mutations .iter() - .find(|m| matches!(m, hammer_core::Mutation::SourcePatch { .. })) + .find(|m| matches!(m, takana_core::Mutation::SourcePatch { .. })) } /// Las superficies del sistema (H4b) que declara el `source_patch` de un `.swm`, o `Slots` vacío /// si el paquete no declara topología. Lo consume el gate de compatibilidad de `install`. -fn source_patch_slots(swm: &hammer_core::Swm) -> hammer_core::Slots { +fn source_patch_slots(swm: &takana_core::Swm) -> takana_core::Slots { match source_patch_of(swm) { - Some(hammer_core::Mutation::SourcePatch { slots, .. }) => slots.clone(), - _ => hammer_core::Slots::default(), + Some(takana_core::Mutation::SourcePatch { slots, .. }) => slots.clone(), + _ => takana_core::Slots::default(), } } @@ -2541,13 +2541,13 @@ fn run_repo_sign( key: &std::path::Path, by: Option<&str>, ) -> anyhow::Result<()> { - let mut index = hammer_core::RepoIndex::load(repo_dir)?; + let mut index = takana_core::RepoIndex::load(repo_dir)?; if index.packages.is_empty() { anyhow::bail!("repo {} vacío: nada que firmar", repo_dir.display()); } let priv_b64 = std::fs::read_to_string(key) .map_err(|e| anyhow::anyhow!("no pude leer la clave {}: {e}", key.display()))?; - let kp = hammer_core::KeyPair::from_private_b64(&priv_b64)?; + let kp = takana_core::KeyPair::from_private_b64(&priv_b64)?; let by = by.map(|s| s.to_string()).unwrap_or_else(|| { key.file_name() .map(|f| f.to_string_lossy().trim_end_matches(".ed25519").to_string()) @@ -2568,25 +2568,25 @@ fn run_repo_verify( repo_dir: &std::path::Path, trust: Option<&std::path::Path>, ) -> anyhow::Result<()> { - let index = hammer_core::RepoIndex::load(repo_dir)?; + let index = takana_core::RepoIndex::load(repo_dir)?; let trust_dir = trust.unwrap_or_else(|| std::path::Path::new(DEFAULT_TRUST_DIR)); - let store = hammer_core::TrustStore::load(trust_dir)?; + let store = takana_core::TrustStore::load(trust_dir)?; match index.verify_signature(&store) { - hammer_core::SigStatus::Trusted { by } => { + takana_core::SigStatus::Trusted { by } => { println!("release: trusted (by {by}) — {} paquete(s)", index.packages.len()); Ok(()) } - hammer_core::SigStatus::UnknownKey { by } => { + takana_core::SigStatus::UnknownKey { by } => { println!( "release: unknown-key (by {by}) — añadí su clave a {} para confiar", trust_dir.display() ); Ok(()) } - hammer_core::SigStatus::BadSig { by, reason } => { + takana_core::SigStatus::BadSig { by, reason } => { anyhow::bail!("release: BAD-SIG (by {by}): {reason} — el índice fue manipulado"); } - hammer_core::SigStatus::Unsigned => { + takana_core::SigStatus::Unsigned => { println!("release: sin firmar (firmá con `hammer repo sign`)"); Ok(()) } @@ -2595,7 +2595,7 @@ fn run_repo_verify( /// Lista los paquetes publicados en un repositorio. fn run_repo_list(repo_dir: &std::path::Path) -> anyhow::Result<()> { - let index = hammer_core::RepoIndex::load(repo_dir)?; + let index = takana_core::RepoIndex::load(repo_dir)?; if index.packages.is_empty() { println!("repo {} vacío (sin index.json o sin paquetes)", repo_dir.display()); return Ok(()); @@ -2631,7 +2631,7 @@ fn run_swm_sign( .map_err(|e| anyhow::anyhow!("no firmo un .swm con schema inválido: {e}"))?; let priv_b64 = std::fs::read_to_string(key) .map_err(|e| anyhow::anyhow!("no pude leer la clave {}: {e}", key.display()))?; - let kp = hammer_core::KeyPair::from_private_b64(&priv_b64)?; + let kp = takana_core::KeyPair::from_private_b64(&priv_b64)?; // `by` por defecto: basename de la clave sin el sufijo `.ed25519`. let by = by.map(|s| s.to_string()).unwrap_or_else(|| { @@ -2673,7 +2673,7 @@ fn run_apply( if let Some(local) = load_local_base(base_ref)? { match swm.verify_base(&local) { - hammer_core::BaseCompat::Ok => {} + takana_core::BaseCompat::Ok => {} other => { print_base_compat(&other); anyhow::bail!("base local no compatible con la base del .swm"); @@ -2681,13 +2681,13 @@ fn run_apply( } } - let mut overlay_id: Option = None; + let mut overlay_id: Option = None; if prefix.is_none() { let root = state_root .map(|p| p.to_path_buf()) - .unwrap_or_else(|| PathBuf::from(hammer_overlay::DEFAULT_STATE_ROOT)); + .unwrap_or_else(|| PathBuf::from(takana_overlay::DEFAULT_STATE_ROOT)); std::fs::create_dir_all(&root)?; - let id = hammer_overlay::try_overlay(&[], &root)?; + let id = takana_overlay::try_overlay(&[], &root)?; eprintln!("overlay {id} abierto"); overlay_id = Some(id); } @@ -2695,21 +2695,21 @@ fn run_apply( let mut counts = (0usize, 0usize, 0usize, 0usize); // src_patch, cfg, init, drop for (i, m) in swm.mutations.iter().enumerate() { match m { - hammer_core::Mutation::SourcePatch { target_bin, .. } => { + takana_core::Mutation::SourcePatch { target_bin, .. } => { counts.0 += 1; if skip_source_patch { eprintln!(" [skip] source_patch #{} → {target_bin}", i + 1); continue; } - let store = hammer_core::Store::open(store_path)?; - let cfg = hammer_build::BuildConfig::from_env_or_defaults(store.root()); - let hash = hammer_build::build_source_patch(m, &cfg, &store, None, pkg_name)?; + let store = takana_core::Store::open(store_path)?; + let cfg = takana_build::BuildConfig::from_env_or_defaults(store.root()); + let hash = takana_build::build_source_patch(m, &cfg, &store, None, pkg_name)?; let artifact = store.find_by_hash(hash.as_str())?; - let into = hammer_core::apply::rebase_path("/", prefix); - let report = hammer_build::run_hydrate( + let into = takana_core::apply::rebase_path("/", prefix); + let report = takana_build::run_hydrate( &artifact, &into, - hammer_core::LinkMode::Static, + takana_core::LinkMode::Static, None, )?; eprintln!( @@ -2720,7 +2720,7 @@ fn run_apply( into.display() ); // Sanity: el target_bin declarado debe existir tras la hidratación. - let abs = hammer_core::apply::rebase_path(target_bin, prefix); + let abs = takana_core::apply::rebase_path(target_bin, prefix); if !abs.exists() { anyhow::bail!( "source_patch declara target_bin={target_bin} pero no quedó en {}", @@ -2729,34 +2729,34 @@ fn run_apply( } created.extend(report.files.iter().map(|f| f.dst.clone())); } - hammer_core::Mutation::ConfigEdit { file: f, inline_diff } => { + takana_core::Mutation::ConfigEdit { file: f, inline_diff } => { counts.1 += 1; - let target = hammer_core::apply::rebase_path(f, prefix); - hammer_core::apply::apply_config_edit(&target, inline_diff)?; + let target = takana_core::apply::rebase_path(f, prefix); + takana_core::apply::apply_config_edit(&target, inline_diff)?; eprintln!(" config_edit #{} → {}", i + 1, target.display()); } - hammer_core::Mutation::InitRule { action, service, command } => { + takana_core::Mutation::InitRule { action, service, command } => { counts.2 += 1; let rules_dir = - hammer_core::apply::rebase_path(hammer_core::apply::INIT_RULES_DIR, prefix); - let p = hammer_core::apply::apply_init_rule(&rules_dir, action, service, command)?; + takana_core::apply::rebase_path(takana_core::apply::INIT_RULES_DIR, prefix); + let p = takana_core::apply::apply_init_rule(&rules_dir, action, service, command)?; eprintln!(" init_rule #{}: {action} {service} → {}", i + 1, p.display()); created.push(p); } - hammer_core::Mutation::FileDrop { path, content_hash, content_b64, content_url } => { + takana_core::Mutation::FileDrop { path, content_hash, content_b64, content_url } => { counts.3 += 1; - let target = hammer_core::apply::rebase_path(path, prefix); + let target = takana_core::apply::rebase_path(path, prefix); match (content_b64, content_url) { (Some(b64), None) => { - hammer_core::apply::apply_file_drop(&target, b64, content_hash)?; + takana_core::apply::apply_file_drop(&target, b64, content_hash)?; eprintln!(" file_drop #{} → {}", i + 1, target.display()); created.push(target.clone()); } (None, Some(url)) => { // Descarga remota (fuera de cualquier sandbox) + verificación BLAKE3 // ANTES de escribir nada: nunca tocamos disco con bytes sin verificar. - let bytes = hammer_build::download::fetch_url_bytes(url)?; - hammer_core::apply::write_filedrop_bytes(&target, &bytes, content_hash)?; + let bytes = takana_build::download::fetch_url_bytes(url)?; + takana_core::apply::write_filedrop_bytes(&target, &bytes, content_hash)?; eprintln!( " file_drop #{} ← {url} ({} bytes) → {}", i + 1, @@ -2800,7 +2800,7 @@ fn run_export( ) -> anyhow::Result<()> { use std::collections::BTreeMap; - let j = hammer_journal::Journal::open(journal_dir)?; + let j = takana_journal::Journal::open(journal_dir)?; let events = j.read_all()?; let filtered: Vec<_> = match since { Some(t) => events.into_iter().filter(|e| e.ts.as_str() > t).collect(), @@ -2808,13 +2808,13 @@ fn run_export( }; let base = match load_local_base(base_ref_path)? { - Some(local) => hammer_core::Base { + Some(local) => takana_core::Base { distro_version: local.distro_version, pins: local.pins, }, None => { eprintln!("warning: sin --base-ref; emitiendo base con distro_version='unknown'"); - hammer_core::Base { + takana_core::Base { distro_version: "unknown".into(), pins: BTreeMap::new(), } @@ -2823,7 +2823,7 @@ fn run_export( // El store es opcional: si el directorio no existe, seguimos en modo "todo file_drop" // (igual que el comportamiento pre-provenance). El receptor no nota la diferencia. - let store_opt = match hammer_core::Store::open(store_root) { + let store_opt = match takana_core::Store::open(store_root) { Ok(s) => Some(s), Err(e) => { eprintln!( @@ -2835,7 +2835,7 @@ fn run_export( let (mutations, stats) = build_export_mutations(&filtered, store_opt.as_ref()); - let swm = hammer_core::Swm { + let swm = takana_core::Swm { swm_version: 1, base, mutations, @@ -2883,16 +2883,16 @@ struct ExportStats { /// 4. Por cada evento de fallback: leemos el contenido actual del disco, codificamos /// base64 y emitimos `file_drop`. Si la lectura falla, contamos warning y omitimos. fn build_export_mutations( - events: &[hammer_journal::MutationEvent], - store: Option<&hammer_core::Store>, -) -> (Vec, ExportStats) { + events: &[takana_journal::MutationEvent], + store: Option<&takana_core::Store>, +) -> (Vec, ExportStats) { use base64::{engine::general_purpose::STANDARD, Engine as _}; use std::collections::BTreeMap; // Paso 1: dedup respetando Delete. - let mut last_by_path: BTreeMap = BTreeMap::new(); + let mut last_by_path: BTreeMap = BTreeMap::new(); for ev in events { - if matches!(ev.op, hammer_journal::MutationOp::Delete) { + if matches!(ev.op, takana_journal::MutationOp::Delete) { last_by_path.remove(&ev.path); continue; } @@ -2906,8 +2906,8 @@ fn build_export_mutations( // // Estructura: artifact_hash → (Recipe, Vec). Los paths se ordenarán antes de // emitir, para que el target_bin sea determinista (importante para tests). - let mut groups: BTreeMap)> = BTreeMap::new(); - let mut fallback: Vec<(PathBuf, &hammer_journal::MutationEvent)> = Vec::new(); + let mut groups: BTreeMap)> = BTreeMap::new(); + let mut fallback: Vec<(PathBuf, &takana_journal::MutationEvent)> = Vec::new(); let mut artifacts_seen: std::collections::BTreeSet = std::collections::BTreeSet::new(); let mut artifacts_without_recipe: std::collections::BTreeSet = @@ -2915,8 +2915,8 @@ fn build_export_mutations( for (path, ev) in &last_by_path { let artifact = match &ev.by.source { - hammer_journal::Source::HammerHydrate { artifact } => Some(artifact.clone()), - hammer_journal::Source::HammerCommit { artifact: Some(a), .. } => Some(a.clone()), + takana_journal::Source::HammerHydrate { artifact } => Some(artifact.clone()), + takana_journal::Source::HammerCommit { artifact: Some(a), .. } => Some(a.clone()), _ => None, }; let Some(art) = artifact else { @@ -2950,7 +2950,7 @@ fn build_export_mutations( stats.missing_recipe = artifacts_without_recipe.len(); - let mut mutations: Vec = Vec::new(); + let mut mutations: Vec = Vec::new(); // Paso 3: source_patches (ordenados por artifact_hash para estabilidad del output). for (art_hash, (recipe, mut paths)) in groups { @@ -2963,15 +2963,15 @@ fn build_export_mutations( // Convertimos la Recipe a los campos de origen que SourcePatch necesita // (git xor tarball — ambos se modelan ya, sin caer a file_drop). let (repo, commit, tarball, sha256) = match recipe.source.kind() { - Ok(hammer_core::SourceKind::Git { repo, commit }) => { + Ok(takana_core::SourceKind::Git { repo, commit }) => { (Some(repo.to_string()), Some(commit.to_string()), None, None) } - Ok(hammer_core::SourceKind::Tarball { url, sha256 }) => { + Ok(takana_core::SourceKind::Tarball { url, sha256 }) => { (None, None, Some(url.to_string()), Some(sha256.to_string())) } // El árbol de una receta derivada no se puede mandar en un `.swm` (no hay puntero // resoluble del otro lado) ⇒ mismo tratamiento que un source inválido: file_drop. - Ok(hammer_core::SourceKind::Dir { .. }) | Err(_) => { + Ok(takana_core::SourceKind::Dir { .. }) | Err(_) => { stats.warnings += 1; eprintln!( "warning: receta de {art_hash} tiene source inválido; cayendo a file_drop" @@ -2999,7 +2999,7 @@ fn build_export_mutations( ); } - mutations.push(hammer_core::Mutation::SourcePatch { + mutations.push(takana_core::Mutation::SourcePatch { repo, commit, tarball, @@ -3008,7 +3008,7 @@ fn build_export_mutations( .then_some(recipe.source.strip_components), patch: patch_inline, patch_url: None, - build: hammer_core::SwmBuild { + build: takana_core::SwmBuild { compiler: recipe.build.compiler.as_str().to_string(), target: recipe.build.target.clone(), link: recipe.build.link.as_str().to_string(), @@ -3045,9 +3045,9 @@ fn build_export_mutations( continue; } }; - let h = hammer_core::ArtifactHash::of_inputs(&[bytes.as_slice()]); + let h = takana_core::ArtifactHash::of_inputs(&[bytes.as_slice()]); let b64 = STANDARD.encode(&bytes); - mutations.push(hammer_core::Mutation::FileDrop { + mutations.push(takana_core::Mutation::FileDrop { path: path.display().to_string(), content_hash: h.as_str().to_string(), content_b64: Some(b64), @@ -3064,7 +3064,7 @@ fn build_export_mutations( /// patches, devuelve `None`. Si algún patch no se puede leer, devuelve `None` y deja un /// warning en stderr — el receptor reconstruirá sin patches y verificará con /// `expected_hash` que el binario coincide, así que el error es detectable. -fn collect_patches_inline(recipe: &hammer_core::Recipe) -> Option { +fn collect_patches_inline(recipe: &takana_core::Recipe) -> Option { if recipe.source.patches.is_empty() { return None; } @@ -3104,7 +3104,7 @@ fn run_ai( repair_max_attempts: Option, repair_window_ms: u64, ) -> anyhow::Result<()> { - use hammer_agent::orchestrator::{ApplyTarget, CompileMode, RepairPolicy}; + use takana_agent::orchestrator::{ApplyTarget, CompileMode, RepairPolicy}; if llm && catalog.is_some() { anyhow::bail!("--llm y --catalog son mutuamente excluyentes"); @@ -3131,7 +3131,7 @@ fn run_ai( None => ApplyTarget::Overlay { state_root: state_root .map(|p| p.to_path_buf()) - .unwrap_or_else(|| PathBuf::from(hammer_overlay::DEFAULT_STATE_ROOT)), + .unwrap_or_else(|| PathBuf::from(takana_overlay::DEFAULT_STATE_ROOT)), }, }; @@ -3219,11 +3219,11 @@ fn infer_base_for_catalog( intent: &str, catalog: &std::path::Path, base_ref: Option<&std::path::Path>, -) -> anyhow::Result { +) -> anyhow::Result { if let Some(b) = load_local_base(base_ref)? { return Ok(b); } - let cat = hammer_agent::IntentCatalog::load_from_path(catalog) + let cat = takana_agent::IntentCatalog::load_from_path(catalog) .map_err(|e| anyhow::anyhow!("catálogo {}: {e}", catalog.display()))?; let base_dir = catalog.parent().unwrap_or_else(|| std::path::Path::new(".")); let ctx_swm = cat @@ -3239,10 +3239,10 @@ fn infer_base_for_catalog( .find(|e| e.intent == intent) .and_then(|e| e.swm_path.as_ref()) .and_then(|p| std::fs::read_to_string(base_dir.join(p)).ok()) - .and_then(|t| hammer_core::Swm::from_yaml(&t).ok()) + .and_then(|t| takana_core::Swm::from_yaml(&t).ok()) }); match ctx_swm { - Some(s) => Ok(hammer_core::BaseRef::from(&s.base)), + Some(s) => Ok(takana_core::BaseRef::from(&s.base)), None => anyhow::bail!("no pude inferir BaseRef sin --base-ref"), } } @@ -3250,12 +3250,12 @@ fn infer_base_for_catalog( fn run_with_mock_translator( intent: &str, catalog: &std::path::Path, - base: hammer_core::BaseRef, - apply: hammer_agent::orchestrator::ApplyTarget, - compile: hammer_agent::orchestrator::CompileMode, - policy: Option<&hammer_agent::orchestrator::RepairPolicy>, -) -> anyhow::Result { - use hammer_agent::{IntentCatalog, MockTranslator, Orchestrator}; + base: takana_core::BaseRef, + apply: takana_agent::orchestrator::ApplyTarget, + compile: takana_agent::orchestrator::CompileMode, + policy: Option<&takana_agent::orchestrator::RepairPolicy>, +) -> anyhow::Result { + use takana_agent::{IntentCatalog, MockTranslator, Orchestrator}; let cat = IntentCatalog::load_from_path(catalog) .map_err(|e| anyhow::anyhow!("catálogo {}: {e}", catalog.display()))?; let base_dir = catalog.parent().unwrap_or_else(|| std::path::Path::new(".")); @@ -3275,12 +3275,12 @@ fn run_with_mock_translator( #[cfg(feature = "llm-claude")] fn run_with_llm_translator( intent: &str, - base: hammer_core::BaseRef, - apply: hammer_agent::orchestrator::ApplyTarget, - compile: hammer_agent::orchestrator::CompileMode, - policy: Option<&hammer_agent::orchestrator::RepairPolicy>, -) -> anyhow::Result { - use hammer_agent::{ClaudeConfig, ClaudeTranslator, Orchestrator}; + base: takana_core::BaseRef, + apply: takana_agent::orchestrator::ApplyTarget, + compile: takana_agent::orchestrator::CompileMode, + policy: Option<&takana_agent::orchestrator::RepairPolicy>, +) -> anyhow::Result { + use takana_agent::{ClaudeConfig, ClaudeTranslator, Orchestrator}; let cfg = ClaudeConfig::from_env() .map_err(|e| anyhow::anyhow!("ClaudeConfig::from_env: {e}"))?; let translator = ClaudeTranslator::new(cfg); @@ -3298,11 +3298,11 @@ fn run_with_llm_translator( #[cfg(not(feature = "llm-claude"))] fn run_with_llm_translator( _intent: &str, - _base: hammer_core::BaseRef, - _apply: hammer_agent::orchestrator::ApplyTarget, - _compile: hammer_agent::orchestrator::CompileMode, - _policy: Option<&hammer_agent::orchestrator::RepairPolicy>, -) -> anyhow::Result { + _base: takana_core::BaseRef, + _apply: takana_agent::orchestrator::ApplyTarget, + _compile: takana_agent::orchestrator::CompileMode, + _policy: Option<&takana_agent::orchestrator::RepairPolicy>, +) -> anyhow::Result { anyhow::bail!( "este binario se compiló sin el feature `llm-claude`. Recompila: \ `cargo build -p hammer-cli --features llm-claude` (o desactiva --llm)." @@ -3316,14 +3316,14 @@ fn run_query( base_ref: Option<&std::path::Path>, fs_root: Option<&std::path::Path>, ) -> anyhow::Result<()> { - let mut ctx = hammer_core::query::EvalContext::new(); + let mut ctx = takana_core::query::EvalContext::new(); if let Some(b) = load_local_base(base_ref)? { ctx = ctx.with_base(b); } if let Some(r) = fs_root { ctx = ctx.with_fs_root(r.to_path_buf()); } - let value = hammer_core::query::eval_str(expr, &ctx); + let value = takana_core::query::eval_str(expr, &ctx); let json = serde_json::to_string_pretty(&value)?; println!("{json}"); Ok(()) @@ -3355,7 +3355,7 @@ fn run_ctl(line: &str, fifo: &std::path::Path) -> anyhow::Result<()> { /// Parsea un `--swap name=hash[:rel_path]` (variante b del builder, SDD 11 §7.2b). El `rel_path` /// por defecto es `usr/bin/`. Quitamos el prefijo `b3:` del hash ANTES de buscar el `:` del /// rel_path opcional — si no, `make=b3:abc` se parsearía como hash=`b3`, rel_path=`abc`. -fn parse_swap(s: &str) -> anyhow::Result { +fn parse_swap(s: &str) -> anyhow::Result { let (name, rest) = s .split_once('=') .ok_or_else(|| anyhow::anyhow!("--swap '{s}': falta '=' (name=hash[:rel_path])"))?; @@ -3364,9 +3364,9 @@ fn parse_swap(s: &str) -> anyhow::Result { Some((h, p)) => (h, p.to_string()), None => (rest, format!("usr/bin/{name}")), }; - Ok(hammer_bootstrap::ToolchainSwap { + Ok(takana_bootstrap::ToolchainSwap { name: name.to_string(), - artifact: hammer_core::ArtifactHash::from_hex(hash), + artifact: takana_core::ArtifactHash::from_hex(hash), rel_path, }) } @@ -3424,7 +3424,7 @@ mod swap_tests { #[cfg(test)] mod export_tests { use super::*; - use hammer_journal::{Actor, MutationEvent, MutationOp, Source}; + use takana_journal::{Actor, MutationEvent, MutationOp, Source}; fn write_recipe_sidecar(art_dir: &std::path::Path, name: &str, commit: &str) { std::fs::create_dir_all(art_dir.join(".hammer")).unwrap(); @@ -3442,7 +3442,7 @@ link = "static" flags = ["--enable-foo"] "# ); - std::fs::write(art_dir.join(hammer_core::store::RECIPE_SIDECAR_REL), toml).unwrap(); + std::fs::write(art_dir.join(takana_core::store::RECIPE_SIDECAR_REL), toml).unwrap(); } fn ev_hydrate(path: &str, artifact: &str) -> MutationEvent { @@ -3482,7 +3482,7 @@ flags = ["--enable-foo"] let (mutations, stats) = build_export_mutations(&events, None); assert_eq!(stats.source_patches, 0); assert_eq!(stats.file_drops, 1); - assert!(matches!(mutations[0], hammer_core::Mutation::FileDrop { .. })); + assert!(matches!(mutations[0], takana_core::Mutation::FileDrop { .. })); } #[test] @@ -3505,7 +3505,7 @@ flags = ["--enable-foo"] fn hydrate_with_recipe_sidecar_emits_source_patch() { let d = tempfile::tempdir().unwrap(); let store_root = d.path().join("store"); - let store = hammer_core::Store::open(&store_root).unwrap(); + let store = takana_core::Store::open(&store_root).unwrap(); let art_dir = store_root.join("cafe1234-grep"); write_recipe_sidecar(&art_dir, "grep", "deadbeef"); @@ -3526,7 +3526,7 @@ flags = ["--enable-foo"] assert_eq!(stats.file_drops, 0); assert_eq!(stats.missing_recipe, 0); match &mutations[0] { - hammer_core::Mutation::SourcePatch { + takana_core::Mutation::SourcePatch { repo, commit, build, @@ -3552,7 +3552,7 @@ flags = ["--enable-foo"] fn hydrate_without_recipe_falls_back_to_file_drop() { let d = tempfile::tempdir().unwrap(); let store_root = d.path().join("store"); - let store = hammer_core::Store::open(&store_root).unwrap(); + let store = takana_core::Store::open(&store_root).unwrap(); // Creamos el artefacto SIN sidecar. std::fs::create_dir_all(store_root.join("badbeef-grep")).unwrap(); @@ -3565,14 +3565,14 @@ flags = ["--enable-foo"] assert_eq!(stats.source_patches, 0); assert_eq!(stats.file_drops, 1); assert_eq!(stats.missing_recipe, 1, "debe contar el artefacto sin sidecar"); - assert!(matches!(mutations[0], hammer_core::Mutation::FileDrop { .. })); + assert!(matches!(mutations[0], takana_core::Mutation::FileDrop { .. })); } #[test] fn mixed_traceable_and_external_emit_both_kinds() { let d = tempfile::tempdir().unwrap(); let store_root = d.path().join("store"); - let store = hammer_core::Store::open(&store_root).unwrap(); + let store = takana_core::Store::open(&store_root).unwrap(); let art_dir = store_root.join("aaaa1111-grep"); write_recipe_sidecar(&art_dir, "grep", "feedface"); @@ -3591,8 +3591,8 @@ flags = ["--enable-foo"] assert_eq!(stats.source_patches, 1); assert_eq!(stats.file_drops, 1); // Orden: source_patches primero (BTreeMap por hash), luego file_drops. - assert!(matches!(mutations[0], hammer_core::Mutation::SourcePatch { .. })); - assert!(matches!(mutations[1], hammer_core::Mutation::FileDrop { .. })); + assert!(matches!(mutations[0], takana_core::Mutation::SourcePatch { .. })); + assert!(matches!(mutations[1], takana_core::Mutation::FileDrop { .. })); } #[test] diff --git a/crates/hammer-cli/src/nix_import.rs b/crates/takana-cli/src/nix_import.rs similarity index 98% rename from crates/hammer-cli/src/nix_import.rs rename to crates/takana-cli/src/nix_import.rs index 26ed1435..7e53d90f 100644 --- a/crates/hammer-cli/src/nix_import.rs +++ b/crates/takana-cli/src/nix_import.rs @@ -417,7 +417,7 @@ mod tests { let pkg: NixPkg = serde_json::from_str(json).unwrap(); let toml = to_recipe_toml(&pkg).unwrap(); // Parsea como Recipe válida de hammer. - let recipe = hammer_core::Recipe::from_toml(&toml).expect("recipe válida"); + let recipe = takana_core::Recipe::from_toml(&toml).expect("recipe válida"); assert_eq!(recipe.name, "hello"); assert_eq!(recipe.version, "2.12.1"); // mirror://gnu/ se traduce a una URL concreta que el fetch de hammer entiende. @@ -438,7 +438,7 @@ mod tests { "is_rust": true, "main_program": "rg" }"#; let pkg: NixPkg = serde_json::from_str(json).unwrap(); - let recipe = hammer_core::Recipe::from_toml(&to_recipe_toml(&pkg).unwrap()).unwrap(); + let recipe = takana_core::Recipe::from_toml(&to_recipe_toml(&pkg).unwrap()).unwrap(); assert_eq!(recipe.build.flags, vec!["--bin", "rg"]); let inst = recipe.build.phases.install.as_deref().unwrap(); assert!(inst.contains("cp target/release/rg /out/usr/bin/rg"), "{inst}"); @@ -456,7 +456,7 @@ mod tests { }"#; let pkg: NixPkg = serde_json::from_str(json).unwrap(); let toml = to_recipe_toml(&pkg).unwrap(); - let recipe = hammer_core::Recipe::from_toml(&toml).unwrap(); + let recipe = takana_core::Recipe::from_toml(&toml).unwrap(); assert!(recipe.deps.build.is_empty(), "Rust no emite deps activas: {:?}", recipe.deps.build); assert!(toml.contains("# buildInputs de nix"), "deja provenance comentada: {toml}"); assert!(toml.contains("pcre2"), "lista los nombres en el comentario: {toml}"); @@ -471,7 +471,7 @@ mod tests { "native_build_inputs": ["install-shell-files", "version-check-hook"] }"#; let pkg: NixPkg = serde_json::from_str(json).unwrap(); - let recipe = hammer_core::Recipe::from_toml(&to_recipe_toml(&pkg).unwrap()).unwrap(); + let recipe = takana_core::Recipe::from_toml(&to_recipe_toml(&pkg).unwrap()).unwrap(); // pcre2 sobrevive (paquete real); hooks/wrappers/shell-files y el toolchain rustc/cargo // se filtran (rustc/cargo son el lab, no deps). assert_eq!(recipe.deps.build, vec!["pcre2"]); @@ -503,7 +503,7 @@ mod tests { }"#; let pkg: NixPkg = serde_json::from_str(json).unwrap(); let toml = to_recipe_toml(&pkg).unwrap(); - let recipe = hammer_core::Recipe::from_toml(&toml).unwrap(); + let recipe = takana_core::Recipe::from_toml(&toml).unwrap(); assert_eq!(recipe.source.repo.as_deref(), Some("https://github.com/BurntSushi/ripgrep")); assert_eq!( recipe.source.commit.as_deref(), diff --git a/crates/hammer-cli/src/qorpa.rs b/crates/takana-cli/src/qorpa.rs similarity index 99% rename from crates/hammer-cli/src/qorpa.rs rename to crates/takana-cli/src/qorpa.rs index 27a52e76..114fe734 100644 --- a/crates/hammer-cli/src/qorpa.rs +++ b/crates/takana-cli/src/qorpa.rs @@ -293,7 +293,7 @@ fn pull( download_to_file(url, &archive)?; // El corte. Si el contenido no es el que dice ser, se ABORTA — no se avisa y se sigue. - hammer_build::download::verify_sha256(&archive, &sha).inspect_err(|_| { + takana_build::download::verify_sha256(&archive, &sha).inspect_err(|_| { std::fs::remove_file(&archive).ok(); })?; let archive_bytes = std::fs::metadata(&archive)?.len(); @@ -636,7 +636,7 @@ fn write_manifest(dir: &Path, m: &ImageManifest) -> Result<()> { // importada del store y la traída con `pull` serían dos imágenes distintas con los mismos bytes, y // las instancias de dos máquinas dejarían de coincidir — justo lo que el pin existe para evitar. fn import(root: &Path, store: &Path, hash: &str, copiar: bool) -> Result<()> { - let store = hammer_core::store::Store::open(store) + let store = takana_core::store::Store::open(store) .map_err(|e| anyhow::anyhow!("abriendo el store: {e}"))?; let art = store.find_by_hash(hash) .map_err(|e| anyhow::anyhow!("{e}"))?; diff --git a/crates/hammer-cli/src/qorpa_wl.rs b/crates/takana-cli/src/qorpa_wl.rs similarity index 100% rename from crates/hammer-cli/src/qorpa_wl.rs rename to crates/takana-cli/src/qorpa_wl.rs diff --git a/crates/hammer-cli/tests/boot_menu.rs b/crates/takana-cli/tests/boot_menu.rs similarity index 100% rename from crates/hammer-cli/tests/boot_menu.rs rename to crates/takana-cli/tests/boot_menu.rs diff --git a/crates/hammer-cli/tests/bootstrap_cli.rs b/crates/takana-cli/tests/bootstrap_cli.rs similarity index 100% rename from crates/hammer-cli/tests/bootstrap_cli.rs rename to crates/takana-cli/tests/bootstrap_cli.rs diff --git a/crates/hammer-cli/tests/compat_gate.rs b/crates/takana-cli/tests/compat_gate.rs similarity index 99% rename from crates/hammer-cli/tests/compat_gate.rs rename to crates/takana-cli/tests/compat_gate.rs index 8d043496..4053bbed 100644 --- a/crates/hammer-cli/tests/compat_gate.rs +++ b/crates/takana-cli/tests/compat_gate.rs @@ -8,7 +8,7 @@ use std::process::Command; use base64::{engine::general_purpose::STANDARD, Engine as _}; -use hammer_core::ArtifactHash; +use takana_core::ArtifactHash; #[test] fn install_aborta_ante_colision_de_fichero_y_force_slots_la_supera() { diff --git a/crates/hammer-cli/tests/swm_roundtrip.rs b/crates/takana-cli/tests/swm_roundtrip.rs similarity index 97% rename from crates/hammer-cli/tests/swm_roundtrip.rs rename to crates/takana-cli/tests/swm_roundtrip.rs index bbac6b68..50435858 100644 --- a/crates/hammer-cli/tests/swm_roundtrip.rs +++ b/crates/takana-cli/tests/swm_roundtrip.rs @@ -10,9 +10,9 @@ use std::collections::BTreeMap; use std::path::Path; use base64::{engine::general_purpose::STANDARD, Engine as _}; -use hammer_core::apply::{apply_config_edit, apply_file_drop, rebase_path, verify_content_hash}; -use hammer_core::swm::{Base, BaseCompat, BaseRef, Mutation, Swm}; -use hammer_core::ArtifactHash; +use takana_core::apply::{apply_config_edit, apply_file_drop, rebase_path, verify_content_hash}; +use takana_core::swm::{Base, BaseCompat, BaseRef, Mutation, Swm}; +use takana_core::ArtifactHash; fn write(p: &Path, content: &str) { if let Some(parent) = p.parent() { diff --git a/crates/hammer-core/Cargo.toml b/crates/takana-core/Cargo.toml similarity index 96% rename from crates/hammer-core/Cargo.toml rename to crates/takana-core/Cargo.toml index aa5d189f..d322b681 100644 --- a/crates/hammer-core/Cargo.toml +++ b/crates/takana-core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-core" +name = "takana-core" version.workspace = true edition.workspace = true license.workspace = true diff --git a/crates/hammer-core/src/apply.rs b/crates/takana-core/src/apply.rs similarity index 100% rename from crates/hammer-core/src/apply.rs rename to crates/takana-core/src/apply.rs diff --git a/crates/hammer-core/src/caps.rs b/crates/takana-core/src/caps.rs similarity index 100% rename from crates/hammer-core/src/caps.rs rename to crates/takana-core/src/caps.rs diff --git a/crates/hammer-core/src/compat.rs b/crates/takana-core/src/compat.rs similarity index 100% rename from crates/hammer-core/src/compat.rs rename to crates/takana-core/src/compat.rs diff --git a/crates/hammer-core/src/differs.rs b/crates/takana-core/src/differs.rs similarity index 100% rename from crates/hammer-core/src/differs.rs rename to crates/takana-core/src/differs.rs diff --git a/crates/hammer-core/src/hash.rs b/crates/takana-core/src/hash.rs similarity index 100% rename from crates/hammer-core/src/hash.rs rename to crates/takana-core/src/hash.rs diff --git a/crates/hammer-core/src/installed.rs b/crates/takana-core/src/installed.rs similarity index 100% rename from crates/hammer-core/src/installed.rs rename to crates/takana-core/src/installed.rs diff --git a/crates/hammer-core/src/kernel/catalog.rs b/crates/takana-core/src/kernel/catalog.rs similarity index 100% rename from crates/hammer-core/src/kernel/catalog.rs rename to crates/takana-core/src/kernel/catalog.rs diff --git a/crates/hammer-core/src/kernel/config.rs b/crates/takana-core/src/kernel/config.rs similarity index 100% rename from crates/hammer-core/src/kernel/config.rs rename to crates/takana-core/src/kernel/config.rs diff --git a/crates/hammer-core/src/kernel/contract.rs b/crates/takana-core/src/kernel/contract.rs similarity index 100% rename from crates/hammer-core/src/kernel/contract.rs rename to crates/takana-core/src/kernel/contract.rs diff --git a/crates/hammer-core/src/kernel/gate.rs b/crates/takana-core/src/kernel/gate.rs similarity index 100% rename from crates/hammer-core/src/kernel/gate.rs rename to crates/takana-core/src/kernel/gate.rs diff --git a/crates/hammer-core/src/kernel/hw.rs b/crates/takana-core/src/kernel/hw.rs similarity index 100% rename from crates/hammer-core/src/kernel/hw.rs rename to crates/takana-core/src/kernel/hw.rs diff --git a/crates/hammer-core/src/kernel/kconfig.rs b/crates/takana-core/src/kernel/kconfig.rs similarity index 100% rename from crates/hammer-core/src/kernel/kconfig.rs rename to crates/takana-core/src/kernel/kconfig.rs diff --git a/crates/hammer-core/src/kernel/mod.rs b/crates/takana-core/src/kernel/mod.rs similarity index 100% rename from crates/hammer-core/src/kernel/mod.rs rename to crates/takana-core/src/kernel/mod.rs diff --git a/crates/hammer-core/src/kernel/modmap.rs b/crates/takana-core/src/kernel/modmap.rs similarity index 100% rename from crates/hammer-core/src/kernel/modmap.rs rename to crates/takana-core/src/kernel/modmap.rs diff --git a/crates/hammer-core/src/kernel/plan.rs b/crates/takana-core/src/kernel/plan.rs similarity index 100% rename from crates/hammer-core/src/kernel/plan.rs rename to crates/takana-core/src/kernel/plan.rs diff --git a/crates/hammer-core/src/kernel/reverse.rs b/crates/takana-core/src/kernel/reverse.rs similarity index 100% rename from crates/hammer-core/src/kernel/reverse.rs rename to crates/takana-core/src/kernel/reverse.rs diff --git a/crates/hammer-core/src/lab.rs b/crates/takana-core/src/lab.rs similarity index 100% rename from crates/hammer-core/src/lab.rs rename to crates/takana-core/src/lab.rs diff --git a/crates/hammer-core/src/lib.rs b/crates/takana-core/src/lib.rs similarity index 100% rename from crates/hammer-core/src/lib.rs rename to crates/takana-core/src/lib.rs diff --git a/crates/hammer-core/src/proto.rs b/crates/takana-core/src/proto.rs similarity index 98% rename from crates/hammer-core/src/proto.rs rename to crates/takana-core/src/proto.rs index 7c574c7e..e354c159 100644 --- a/crates/hammer-core/src/proto.rs +++ b/crates/takana-core/src/proto.rs @@ -41,7 +41,7 @@ pub enum Command { /// Consulta de estado. `what` decide qué campos se usan: /// - `"file"`: usa `path` (metadata del archivo). /// - `"artifact"`: usa `name` o `path` (busca un hash en el store). - /// - `"expr"`: usa `expr`, una expresión del mini-lenguaje (ver `hammer_core::query`). + /// - `"expr"`: usa `expr`, una expresión del mini-lenguaje (ver `takana_core::query`). Query { what: String, #[serde(default, skip_serializing_if = "Option::is_none")] @@ -162,9 +162,9 @@ pub struct Peer { pub pid: i32, } -/// [H1c] Forma serializable del `EvidenceReport` de `hammer_build` que viaja en `BuildReady`. +/// [H1c] Forma serializable del `EvidenceReport` de `takana_build` que viaja en `BuildReady`. /// El lado del build (hammerd) ejecuta la evidencia y la adjunta; el orquestador la lee sin -/// depender de `hammer_build` (la separación agente-PROPONE / lab-CONSTRUYE se preserva). +/// depender de `takana_build` (la separación agente-PROPONE / lab-CONSTRUYE se preserva). #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct EvidenceVerdict { /// Gate: `false` ⇒ al menos un check declarado falló ⇒ el orquestador no propone la mutación. diff --git a/crates/hammer-core/src/query.rs b/crates/takana-core/src/query.rs similarity index 100% rename from crates/hammer-core/src/query.rs rename to crates/takana-core/src/query.rs diff --git a/crates/hammer-core/src/recipe.rs b/crates/takana-core/src/recipe.rs similarity index 100% rename from crates/hammer-core/src/recipe.rs rename to crates/takana-core/src/recipe.rs diff --git a/crates/hammer-core/src/repo.rs b/crates/takana-core/src/repo.rs similarity index 100% rename from crates/hammer-core/src/repo.rs rename to crates/takana-core/src/repo.rs diff --git a/crates/hammer-core/src/sign.rs b/crates/takana-core/src/sign.rs similarity index 100% rename from crates/hammer-core/src/sign.rs rename to crates/takana-core/src/sign.rs diff --git a/crates/hammer-core/src/store.rs b/crates/takana-core/src/store.rs similarity index 100% rename from crates/hammer-core/src/store.rs rename to crates/takana-core/src/store.rs diff --git a/crates/hammer-core/src/swm.rs b/crates/takana-core/src/swm.rs similarity index 99% rename from crates/hammer-core/src/swm.rs rename to crates/takana-core/src/swm.rs index 58ed963b..15b7c24a 100644 --- a/crates/hammer-core/src/swm.rs +++ b/crates/takana-core/src/swm.rs @@ -244,7 +244,7 @@ impl Swm { /// Construye un `.swm` de un único `source_patch` a partir de una [`crate::Recipe`] del /// corpus — la dirección **forward** que cierra la paquetería (Etapa F): una receta que el /// sistema YA sabe construir se vuelve un paquete distribuible y reproducible-desde-fuente. - /// Es la inversa de `hammer_build::swm_bridge` (que va `source_patch` → `Recipe` → build). + /// Es la inversa de `takana_build::swm_bridge` (que va `source_patch` → `Recipe` → build). /// /// `hammer-core` no toca disco: el caller resuelve y **lee** los patches de la receta /// (relativos a `recipe.base_dir`) y pasa su texto ya concatenado en `patch_text`. El diff --git a/crates/hammer-journal/Cargo.toml b/crates/takana-journal/Cargo.toml similarity index 89% rename from crates/hammer-journal/Cargo.toml rename to crates/takana-journal/Cargo.toml index bf564133..e2e1c718 100644 --- a/crates/hammer-journal/Cargo.toml +++ b/crates/takana-journal/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-journal" +name = "takana-journal" version.workspace = true edition.workspace = true license.workspace = true @@ -8,7 +8,7 @@ repository.workspace = true description = "El diario de mutaciones de hammer: append-only JSON-líneas sobre eventos del FHS." [dependencies] -hammer-core.workspace = true +takana-core.workspace = true anyhow.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/hammer-journal/src/lib.rs b/crates/takana-journal/src/lib.rs similarity index 99% rename from crates/hammer-journal/src/lib.rs rename to crates/takana-journal/src/lib.rs index 199d37a3..3b8347cd 100644 --- a/crates/hammer-journal/src/lib.rs +++ b/crates/takana-journal/src/lib.rs @@ -5,7 +5,7 @@ //! //! Esta crate es **lógica pura**: nada de fanotify ni de mounts. El watcher real vive en //! `hammerd` y empuja eventos aquí vía `Journal::record`. El hook desde -//! `hammer_overlay::commit` también empuja por aquí. +//! `takana_overlay::commit` también empuja por aquí. //! //! Diseño rationale (SDD 05): //! - El diario no bloquea acciones; sólo observa. Pero también acepta eventos "trazables" diff --git a/crates/hammer-mirror/Cargo.toml b/crates/takana-mirror/Cargo.toml similarity index 89% rename from crates/hammer-mirror/Cargo.toml rename to crates/takana-mirror/Cargo.toml index b017236e..e92f2485 100644 --- a/crates/hammer-mirror/Cargo.toml +++ b/crates/takana-mirror/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-mirror" +name = "takana-mirror" version.workspace = true edition.workspace = true license.workspace = true @@ -8,7 +8,7 @@ repository.workspace = true description = "Mirror del store content-addressed de hammer (E3): replica artefactos por hash, verifica of_tree en recepción." [dependencies] -hammer-core.workspace = true +takana-core.workspace = true anyhow.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/hammer-mirror/src/lib.rs b/crates/takana-mirror/src/lib.rs similarity index 99% rename from crates/hammer-mirror/src/lib.rs rename to crates/takana-mirror/src/lib.rs index 4416e289..c313cc2d 100644 --- a/crates/hammer-mirror/src/lib.rs +++ b/crates/takana-mirror/src/lib.rs @@ -20,7 +20,7 @@ use std::path::Path; -use hammer_core::{ArtifactHash, Store}; +use takana_core::{ArtifactHash, Store}; use serde::{Deserialize, Serialize}; #[derive(Debug, thiserror::Error)] @@ -28,7 +28,7 @@ pub enum Error { #[error("io: {0}")] Io(#[from] std::io::Error), #[error("core: {0}")] - Core(#[from] hammer_core::Error), + Core(#[from] takana_core::Error), #[error( "integridad: el artefacto '{dir}' recibido hashea a {got} pero el índice anuncia {want} — \ transferencia corrupta o manipulada; NO se selló" diff --git a/crates/hammer-overlay/Cargo.toml b/crates/takana-overlay/Cargo.toml similarity index 85% rename from crates/hammer-overlay/Cargo.toml rename to crates/takana-overlay/Cargo.toml index ea5c68fd..e987acba 100644 --- a/crates/hammer-overlay/Cargo.toml +++ b/crates/takana-overlay/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-overlay" +name = "takana-overlay" version.workspace = true edition.workspace = true license.workspace = true @@ -8,8 +8,8 @@ repository.workspace = true description = "El overlay de experimentación de hammer: try/commit/discard/status sobre overlayfs." [dependencies] -hammer-core.workspace = true -hammer-journal.workspace = true +takana-core.workspace = true +takana-journal.workspace = true anyhow.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/hammer-overlay/src/lib.rs b/crates/takana-overlay/src/lib.rs similarity index 97% rename from crates/hammer-overlay/src/lib.rs rename to crates/takana-overlay/src/lib.rs index 016a54a2..853c537c 100644 --- a/crates/hammer-overlay/src/lib.rs +++ b/crates/takana-overlay/src/lib.rs @@ -248,7 +248,7 @@ pub fn commit(id: &OverlayId, state_root: &Path) -> Result { pub fn commit_with_journal( id: &OverlayId, state_root: &Path, - journal: &hammer_journal::Journal, + journal: &takana_journal::Journal, ) -> Result { commit_inner(id, state_root, Some(journal)) } @@ -256,7 +256,7 @@ pub fn commit_with_journal( fn commit_inner( id: &OverlayId, state_root: &Path, - journal: Option<&hammer_journal::Journal>, + journal: Option<&takana_journal::Journal>, ) -> Result { let base = state_root.join(id.as_str()); let state_file = base.join("state.json"); @@ -295,11 +295,11 @@ fn commit_inner( } fn record_commit_to_journal( - j: &hammer_journal::Journal, + j: &takana_journal::Journal, id: &OverlayId, report: &CommitReport, ) { - use hammer_journal::{Actor, MutationEvent, MutationOp, Source}; + use takana_journal::{Actor, MutationEvent, MutationOp, Source}; let actor = Actor { source: Source::HammerCommit { overlay: id.as_str().to_string(), @@ -308,7 +308,7 @@ fn record_commit_to_journal( pid: Some(std::process::id()), uid: Some(unsafe { libc::getuid() }), }; - let ts = hammer_journal::now_rfc3339(); + let ts = takana_journal::now_rfc3339(); for p in &report.copied { let ev = MutationEvent { ts: ts.clone(), @@ -665,7 +665,7 @@ mod tests { // No tocamos mount real: ejercitamos directamente la función privada que el commit // delega para anotar al diario. Eso valida el contrato sin necesidad de overlayfs. let d = tempfile::tempdir().unwrap(); - let journal = hammer_journal::Journal::open(d.path().join("journal")).unwrap(); + let journal = takana_journal::Journal::open(d.path().join("journal")).unwrap(); let report = CommitReport { copied: vec![PathBuf::from("/etc/hosts"), PathBuf::from("/bin/grep")], removed: vec![PathBuf::from("/bin/obsoleto")], @@ -678,13 +678,13 @@ mod tests { .iter() .map(|e| (e.op, e.path.display().to_string())) .collect(); - assert!(ops_paths.contains(&(hammer_journal::MutationOp::Replace, "/etc/hosts".into()))); - assert!(ops_paths.contains(&(hammer_journal::MutationOp::Replace, "/bin/grep".into()))); - assert!(ops_paths.contains(&(hammer_journal::MutationOp::Delete, "/bin/obsoleto".into()))); + assert!(ops_paths.contains(&(takana_journal::MutationOp::Replace, "/etc/hosts".into()))); + assert!(ops_paths.contains(&(takana_journal::MutationOp::Replace, "/bin/grep".into()))); + assert!(ops_paths.contains(&(takana_journal::MutationOp::Delete, "/bin/obsoleto".into()))); // Todos comparten el mismo source con overlay id. for e in &events { match &e.by.source { - hammer_journal::Source::HammerCommit { overlay, .. } => { + takana_journal::Source::HammerCommit { overlay, .. } => { assert_eq!(overlay, "1234-1"); } other => panic!("source inesperado: {other:?}"), diff --git a/crates/hammer-overlay/tests/overlayfs_e2e.rs b/crates/takana-overlay/tests/overlayfs_e2e.rs similarity index 98% rename from crates/hammer-overlay/tests/overlayfs_e2e.rs rename to crates/takana-overlay/tests/overlayfs_e2e.rs index 0d3ea434..06305b46 100644 --- a/crates/hammer-overlay/tests/overlayfs_e2e.rs +++ b/crates/takana-overlay/tests/overlayfs_e2e.rs @@ -16,7 +16,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; -use hammer_overlay::{commit, discard, status, try_overlay, OverlayId}; +use takana_overlay::{commit, discard, status, try_overlay, OverlayId}; fn have_bwrap() -> bool { Command::new("bwrap") @@ -197,7 +197,7 @@ fn body_nested_stack() { // --- guard LIFO: no se puede commitear la capa de abajo con la de arriba encima --- match commit(&id1, &state) { - Err(hammer_overlay::Error::Shadowed { id, shadowed_by }) => { + Err(takana_overlay::Error::Shadowed { id, shadowed_by }) => { assert_eq!(id, id1); assert_eq!(shadowed_by, vec![id2.clone()]); } diff --git a/crates/hammer-recover/Cargo.toml b/crates/takana-recover/Cargo.toml similarity index 52% rename from crates/hammer-recover/Cargo.toml rename to crates/takana-recover/Cargo.toml index b8a1d17b..1cc83300 100644 --- a/crates/hammer-recover/Cargo.toml +++ b/crates/takana-recover/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-recover" +name = "takana-recover" version.workspace = true edition.workspace = true license.workspace = true @@ -7,10 +7,13 @@ authors.workspace = true repository.workspace = true description = "Mini-binario de auto-recuperación de upgrades al arranque (E4 #4b): el /sbin/init lo corre para completar/deshacer un apply interrumpido antes de incarnar." +# El PAQUETE se renombra, el BINARIO no: `/usr/sbin/hammer-recover` está copiado en +# sistemas ya instalados y `hammer-live-install.sh` hornea un hook de arranque que lo +# invoca por ese nombre. Renombrar el binario rompe máquinas instaladas. Etapa 6. [[bin]] name = "hammer-recover" path = "src/main.rs" [dependencies] -hammer-upgrade.workspace = true -hammer-journal.workspace = true +takana-upgrade.workspace = true +takana-journal.workspace = true diff --git a/crates/hammer-recover/src/main.rs b/crates/takana-recover/src/main.rs similarity index 91% rename from crates/hammer-recover/src/main.rs rename to crates/takana-recover/src/main.rs index 53672fd9..19826bf0 100644 --- a/crates/hammer-recover/src/main.rs +++ b/crates/takana-recover/src/main.rs @@ -34,7 +34,7 @@ fn main() { let state = env_path("HAMMER_RECOVER_STATE", "/var/lib/hammer/upgrades"); let journal_dir = env_path("HAMMER_RECOVER_JOURNAL", "/var/lib/hammer/journal"); - match hammer_upgrade::pending(&state) { + match takana_upgrade::pending(&state) { Ok(None) => { println!("hammer-recover: sin upgrade interrumpido"); return; @@ -48,11 +48,11 @@ fn main() { } } - let journal = hammer_journal::Journal::open(&journal_dir).ok(); + let journal = takana_journal::Journal::open(&journal_dir).ok(); let j = journal.as_ref(); if force_rollback { - match hammer_upgrade::recover(&store, &root, &state, j, true) { + match takana_upgrade::recover(&store, &root, &state, j, true) { Ok(r) => println!("hammer-recover: DESHECHO (generación {} descartada)", r.generation), Err(e) => eprintln!("hammer-recover: rollback falló: {e}"), } @@ -60,11 +60,11 @@ fn main() { } // Optimista: completar el upgrade. Si el roll-forward falla, deshacer ⇒ FHS consistente igual. - match hammer_upgrade::recover(&store, &root, &state, j, false) { + match takana_upgrade::recover(&store, &root, &state, j, false) { Ok(r) => println!("hammer-recover: COMPLETADO (generación {})", r.generation), Err(e) => { eprintln!("hammer-recover: roll-forward falló ({e}); deshaciendo para dejar el FHS consistente"); - match hammer_upgrade::recover(&store, &root, &state, j, true) { + match takana_upgrade::recover(&store, &root, &state, j, true) { Ok(r) => println!("hammer-recover: DESHECHO tras fallo (generación {})", r.generation), Err(e2) => eprintln!("hammer-recover: rollback de respaldo también falló: {e2}"), } diff --git a/crates/hammer-upgrade/Cargo.toml b/crates/takana-upgrade/Cargo.toml similarity index 84% rename from crates/hammer-upgrade/Cargo.toml rename to crates/takana-upgrade/Cargo.toml index 4b75227a..e486d4ef 100644 --- a/crates/hammer-upgrade/Cargo.toml +++ b/crates/takana-upgrade/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "hammer-upgrade" +name = "takana-upgrade" version.workspace = true edition.workspace = true license.workspace = true @@ -8,8 +8,8 @@ repository.workspace = true description = "Upgrades atómicos de hammer (E4): aplica un árbol Stage1/producto del store al root vivo con generaciones y rollback." [dependencies] -hammer-core.workspace = true -hammer-journal.workspace = true +takana-core.workspace = true +takana-journal.workspace = true anyhow.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/crates/hammer-upgrade/src/boot_graph.rs b/crates/takana-upgrade/src/boot_graph.rs similarity index 99% rename from crates/hammer-upgrade/src/boot_graph.rs rename to crates/takana-upgrade/src/boot_graph.rs index 558a1c3c..daeebf9a 100644 --- a/crates/hammer-upgrade/src/boot_graph.rs +++ b/crates/takana-upgrade/src/boot_graph.rs @@ -22,8 +22,8 @@ use std::collections::HashMap; use std::path::Path; -use hammer_core::ArtifactHash; -use hammer_journal::Journal; +use takana_core::ArtifactHash; +use takana_journal::Journal; use serde::{Deserialize, Serialize}; use crate::{ diff --git a/crates/hammer-upgrade/src/lib.rs b/crates/takana-upgrade/src/lib.rs similarity index 99% rename from crates/hammer-upgrade/src/lib.rs rename to crates/takana-upgrade/src/lib.rs index b99db0e2..44fe62c3 100644 --- a/crates/hammer-upgrade/src/lib.rs +++ b/crates/takana-upgrade/src/lib.rs @@ -3,7 +3,7 @@ //! Aplicar un árbol Stage1/producto **nuevo** al root vivo sin reinstalar, de forma atómica y con //! **rollback** al árbol anterior. El árbol nuevo es un artefacto sellado del store (CAS BLAKE3); el //! "apply" lo proyecta sobre el FHS vivo (`target_root`, normalmente `/`), registra cada cambio en el -//! [diario](hammer_journal) y deja una **generación** nueva. Si algo sale mal, `rollback` revierte +//! [diario](takana_journal) y deja una **generación** nueva. Si algo sale mal, `rollback` revierte //! exactamente al árbol anterior. //! //! ## Modelo de generaciones (inspirado en NixOS, aplicado in-place al FHS) @@ -35,8 +35,8 @@ use std::path::{Path, PathBuf}; -use hammer_core::{ArtifactHash, Store}; -use hammer_journal::{Actor, Journal, MutationEvent, MutationOp, Source}; +use takana_core::{ArtifactHash, Store}; +use takana_journal::{Actor, Journal, MutationEvent, MutationOp, Source}; use serde::{Deserialize, Serialize}; pub mod boot_graph; @@ -48,9 +48,9 @@ pub enum Error { #[error("io: {0}")] Io(#[from] std::io::Error), #[error("core: {0}")] - Core(#[from] hammer_core::Error), + Core(#[from] takana_core::Error), #[error("journal: {0}")] - Journal(#[from] hammer_journal::Error), + Journal(#[from] takana_journal::Error), #[error("json: {0}")] Json(#[from] serde_json::Error), #[error( @@ -789,7 +789,7 @@ fn journal_change(journal: Option<&Journal>, tree_dir: &str, dst: &Path, op: Cha ChangeOp::Removed => MutationOp::Delete, }; let ev = MutationEvent { - ts: hammer_journal::now_rfc3339(), + ts: takana_journal::now_rfc3339(), op: mop, path: dst.to_path_buf(), by: Actor { diff --git a/scripts/alpine-import.sh b/scripts/alpine-import.sh index ab1e82dd..156b9076 100755 --- a/scripts/alpine-import.sh +++ b/scripts/alpine-import.sh @@ -12,7 +12,7 @@ PKG="${1:?uso: alpine-import.sh [main|community]}" REPO="${2:-main}" BRANCH="${ALPINE_BRANCH:-master}" OUTDIR="${OUTDIR:-.}" -HAMMER="${HAMMER:-cargo run -q -p hammer-cli --}" +HAMMER="${HAMMER:-cargo run -q -p takana-cli --}" BASE="https://gitlab.alpinelinux.org/alpine/aports/-/raw/${BRANCH}/${REPO}/${PKG}" apk=$(curl -fsSL "${BASE}/APKBUILD") || { echo "no encontré ${REPO}/${PKG} en aports@${BRANCH}" >&2; exit 1; } diff --git a/scripts/bootstrap-devfs.sh b/scripts/bootstrap-devfs.sh index 8afdc83b..aca3229d 100755 --- a/scripts/bootstrap-devfs.sh +++ b/scripts/bootstrap-devfs.sh @@ -218,7 +218,7 @@ else # imprime (busca «LLD»/«GNU ld»/«GNU gold») y `--enable-lto=cross` necesita un linker con plugin # LLVM; `llvm22-linker-tools` da el LLVMgold.so para GNU ld, pero el camino soportado por # upstream —y el que usa el propio APKBUILD de Alpine con `--enable-linker=lld`— es lld. - # ⚠ DEUDA CONOCIDA: `lld` NO casa ningún prefijo de `TOOLCHAIN_PREFIXES` (hammer-core/src/lab.rs) + # ⚠ DEUDA CONOCIDA: `lld` NO casa ningún prefijo de `TOOLCHAIN_PREFIXES` (takana-core/src/lab.rs) # ⇒ su versión NO entra en la huella del lab. Eso es lo que permite añadirlo HOY sin re-hashear # los 837 artefactos sellados (medido: la huella no se movió), y a la vez es un agujero: dos labs # con distinto lld pueden sellar bytes distintos en la misma dirección. Sólo expone a las recetas diff --git a/scripts/build-repo.sh b/scripts/build-repo.sh index 069375b7..5f29914f 100755 --- a/scripts/build-repo.sh +++ b/scripts/build-repo.sh @@ -21,7 +21,7 @@ REPO="${REPO:-$(pwd)/dist/repo}" STORE="${STORE:-./store}" DISTRO="${DISTRO:-dev}" BUILD_TIMEOUT="${BUILD_TIMEOUT:-90}" -HAMMER="cargo run -q -p hammer-cli --" +HAMMER="cargo run -q -p takana-cli --" rm -rf "$REPO" mkdir -p "$REPO" diff --git a/scripts/consenso.sh b/scripts/consenso.sh index 513c5dc6..d96b01c3 100755 --- a/scripts/consenso.sh +++ b/scripts/consenso.sh @@ -56,7 +56,7 @@ while [ "$i" -le "$N" ]; do --exclude /dist --exclude /tandas --exclude /.dev-fs --exclude /.git --exclude /.scratch \ --exclude '*.png' --exclude '/content*' ./ "root@$ip:/opt/hammer/" >/dev/null 2>&1 hN=$($SSH "root@$ip" "export PATH=\$HOME/.cargo/bin:\$PATH; cd /opt/hammer && \ - cargo build --release -q -p hammer-cli 2>/dev/null; \ + cargo build --release -q -p takana-cli 2>/dev/null; \ timeout ${POR:-900} ./target/release/takana build $RECETA --store \$PWD/store 2>/dev/null \ | grep -oE '^b3:[a-f0-9]{64}' | head -1" 2>/dev/null | tr -d '\r') echo " → ${hN:-FALLÓ}" diff --git a/scripts/farm/cosecha-cron.sh b/scripts/farm/cosecha-cron.sh index aa171d12..942ca0d4 100755 --- a/scripts/farm/cosecha-cron.sh +++ b/scripts/farm/cosecha-cron.sh @@ -228,7 +228,7 @@ fi # granja podaba eso: `store-gc.sh` mira el store, la poda de caché de CI mira la caché de CI, y este # tercer montón crecía sin dueño desde que el store se mudó al volumen. Se recuperaron 70 G. # -# POR QUÉ ES SEGURO: no es una caché. Los dos caminos de `hammer-build/src/fetch.rs` borran el árbol +# POR QUÉ ES SEGURO: no es una caché. Los dos caminos de `takana-build/src/fetch.rs` borran el árbol # y lo re-extraen en CADA build, sin una sola rama que reutilice ⇒ un árbol viejo no acelera nada y # borrarlo no cuesta ni la re-extracción. Lo único que se pierde es el post-mortem del último build # de esa receta, y por eso el suelo son 24 h y no cero. diff --git a/scripts/farm/farm-lab-sync.sh b/scripts/farm/farm-lab-sync.sh index 429f950e..749307e0 100755 --- a/scripts/farm/farm-lab-sync.sh +++ b/scripts/farm/farm-lab-sync.sh @@ -4,7 +4,7 @@ # ── POR QUÉ NO BASTA CON farm-sync ────────────────────────────────────────────────────────────── # `farm-sync.sh` sube el código con `--exclude /.dev-fs`, a propósito: el lab es del entorno, no del # repo. Eso estaba bien cuando el toolchain NO entraba en el hash. Desde el 2026-08-10 sí entra -# (`hammer-core/src/lab.rs`), así que un worker con su lab horneado en la golden —rustc 1.96— sella +# (`takana-core/src/lab.rs`), así que un worker con su lab horneado en la golden —rustc 1.96— sella # en direcciones DISTINTAS a las del hub —1.97— y su trabajo no le sirve a nadie: no es que compile # distinto, es que lo guarda en otra dirección y el hub nunca lo encuentra. # diff --git a/scripts/farm/harkaq-vol.sh b/scripts/farm/harkaq-vol.sh index 665e1b57..9a6a9497 100755 --- a/scripts/farm/harkaq-vol.sh +++ b/scripts/farm/harkaq-vol.sh @@ -83,7 +83,7 @@ EOF ./ "root@$ip:$REMOTE/" >/dev/null $SSH "root@$ip" "MNT=/mnt/cosecha; mkdir -p \$MNT; mount $DEV \$MNT 2>/dev/null || (mkfs.ext4 -q -F $DEV && mount $DEV \$MNT); mkdir -p \$MNT/verdicts \$MNT/logs" scripts/farm/harkaq-farm-setup.sh "$ip" >/dev/null 2>&1 || echo " (setup con avisos, sigo)" - $SSH "root@$ip" "export PATH=\$HOME/.cargo/bin:\$PATH; cd $REMOTE && cargo build --release -q -p hammer-cli 2>&1 | tail -1" + $SSH "root@$ip" "export PATH=\$HOME/.cargo/bin:\$PATH; cd $REMOTE && cargo build --release -q -p takana-cli 2>&1 | tail -1" # Servicio con auto-shutdown (el script harkaq-campana-vol lo maneja). $SSH "root@$ip" "cat > /etc/systemd/system/harkaq-vol.service </dev/null || true; ls target/debug/hammer >/dev/null 2>&1 && echo ' hammer-cli listo ✓' || echo ' OJO: falta target/debug/hammer (cargo build -p hammer-cli)'" +$SSH "root@$IP" "cd $REMOTE && cargo build -q -p takana-cli 2>/dev/null || true; ls target/debug/hammer >/dev/null 2>&1 && echo ' hammer-cli listo ✓' || echo ' OJO: falta target/debug/hammer (cargo build -p takana-cli)'" cat <&2 + echo " ! sin hammer musl ($HAMMER_MUSL) ⇒ el disco no traerá el menú de arranque (cargo build --target x86_64-unknown-linux-musl -p takana-cli)" >&2 fi # /sbin/init: wrapper que emite un marcador a /dev/ttyS0 (sobrevive `quiet`, que suprime el printk # kernel-side) y hace exec de arje-zero. Prueba positiva de que el switch_root llegó al init real. diff --git a/scripts/iso-image.sh b/scripts/iso-image.sh index cb216f77..1bc97e9b 100755 --- a/scripts/iso-image.sh +++ b/scripts/iso-image.sh @@ -121,7 +121,7 @@ if [ "${INSTALLER:-0}" = 1 ]; then RECOVER_BIN="$ROOT/target/x86_64-unknown-linux-musl/release/hammer-recover" if [ ! -x "$RECOVER_BIN" ]; then echo "==> compilando hammer-recover (static musl) para el payload" - cargo build --release --target x86_64-unknown-linux-musl -p hammer-recover --manifest-path "$ROOT/Cargo.toml" >/dev/null 2>&1 + cargo build --release --target x86_64-unknown-linux-musl -p takana-recover --manifest-path "$ROOT/Cargo.toml" >/dev/null 2>&1 fi [ -x "$RECOVER_BIN" ] || { echo "no pude construir hammer-recover (target musl?)" >&2; exit 1; } install -m 0755 "$RECOVER_BIN" "$IPL/hammer-recover" @@ -131,7 +131,7 @@ if [ "${INSTALLER:-0}" = 1 ]; then HAMMER_BIN="$ROOT/target/x86_64-unknown-linux-musl/release/hammer" if [ ! -x "$HAMMER_BIN" ]; then echo "==> compilando hammer CLI (static musl) para el payload" - cargo build --release --target x86_64-unknown-linux-musl -p hammer-cli --manifest-path "$ROOT/Cargo.toml" >/dev/null 2>&1 + cargo build --release --target x86_64-unknown-linux-musl -p takana-cli --manifest-path "$ROOT/Cargo.toml" >/dev/null 2>&1 fi [ -x "$HAMMER_BIN" ] || { echo "no pude construir el CLI hammer (target musl?)" >&2; exit 1; } install -m 0755 "$HAMMER_BIN" "$IPL/hammer" diff --git a/scripts/lab-image.sh b/scripts/lab-image.sh index 221c5853..7fd82bef 100755 --- a/scripts/lab-image.sh +++ b/scripts/lab-image.sh @@ -2,7 +2,7 @@ # lab-image.sh — empaqueta y publica el ROOTFS YA BOOTSTRAPEADO como imagen pineada por sha256. # # ── POR QUÉ EXISTE ────────────────────────────────────────────────────────────────────────────── -# Desde el 2026-08-10 el toolchain del lab entra en `hash_inputs` (ver `hammer-core/src/lab.rs`): +# Desde el 2026-08-10 el toolchain del lab entra en `hash_inputs` (ver `takana-core/src/lab.rs`): # dos máquinas con distinto `rustc` sellan en direcciones distintas. Eso cierra un agujero real # —antes sellaban bytes distintos en la MISMA dirección— pero abre uno operativo: # diff --git a/scripts/nix-import.sh b/scripts/nix-import.sh index f672c00d..74f0969c 100755 --- a/scripts/nix-import.sh +++ b/scripts/nix-import.sh @@ -4,12 +4,12 @@ # nixpkgs es el mayor set de recetas desde fuente; importamos la receta y hammer reconstruye. # # Requiere `nix` (con nix-command). Ej: scripts/nix-import.sh hello > recipes/hello.toml -# Env: NIXPKGS= (default nixpkgs), HAMMER= (default cargo run -q -p hammer-cli --) +# Env: NIXPKGS= (default nixpkgs), HAMMER= (default cargo run -q -p takana-cli --) set -eu ATTR="${1:?uso: nix-import.sh (ej: hello, jq, ripgrep)}" NIXPKGS="${NIXPKGS:-nixpkgs}" -HAMMER="${HAMMER:-cargo run -q -p hammer-cli --}" +HAMMER="${HAMMER:-cargo run -q -p takana-cli --}" # NIX_STORE: si el /nix/store del sistema no es escribible (install single-user incompleta), apuntá # a un store local, p.ej. NIX_STORE="local?root=$HOME/.nixstore". STORE_OPT="" diff --git a/scripts/pin-recipes.sh b/scripts/pin-recipes.sh index aa61215c..645bfae3 100755 --- a/scripts/pin-recipes.sh +++ b/scripts/pin-recipes.sh @@ -6,7 +6,7 @@ # # Ej: scripts/pin-recipes.sh recipes/*.toml | find recipes -name '*.toml' | xargs scripts/pin-recipes.sh set -eu -HAMMER="${HAMMER:-cargo run -q -p hammer-cli --}" +HAMMER="${HAMMER:-cargo run -q -p takana-cli --}" [ "$#" -gt 0 ] || { echo "uso: pin-recipes.sh " >&2; exit 1; } pinned=0; skipped=0; failed="" diff --git a/scripts/poda-fuentes.sh b/scripts/poda-fuentes.sh index 8e992fbf..c8b2ec3e 100755 --- a/scripts/poda-fuentes.sh +++ b/scripts/poda-fuentes.sh @@ -12,7 +12,7 @@ # de cargo, los `.o`, el `vmlinux`. Es RESIDUO DE BUILD, no código. # # ── POR QUÉ BORRARLO NO CUESTA NADA (esto es lo que hace segura la poda) ──────────────────────── -# No es una caché. `hammer-build/src/fetch.rs` tiene exactamente dos caminos —`fetch_git` (línea +# No es una caché. `takana-build/src/fetch.rs` tiene exactamente dos caminos —`fetch_git` (línea # 73) y `fetch_tarball` (línea 234)— y **los dos hacen `remove_dir_all` del árbol y lo re-extraen, # incondicionalmente, en cada build**. No hay ni una rama que reutilice un árbol existente. # diff --git a/scripts/rust-frontier/swap-rust-into-toolchain.sh b/scripts/rust-frontier/swap-rust-into-toolchain.sh index b76420b8..f03218bf 100755 --- a/scripts/rust-frontier/swap-rust-into-toolchain.sh +++ b/scripts/rust-frontier/swap-rust-into-toolchain.sh @@ -16,7 +16,7 @@ # - only /usr/bin/{rustc,cargo} are REPLACED; the originals are backed up to # usr/bin/.alpine so `--restore` can put them back. # The 4/4 rust recipes build NATIVE (target x86_64-linux-musl == SANDBOX_NATIVE_TARGET -# ⇒ no --target, see hammer-build/src/lib.rs:269), so hammer-rustc compiles them for +# ⇒ no --target, see takana-build/src/lib.rs:269), so hammer-rustc compiles them for # its OWN native triple x86_64-unknown-linux-musl. # # Usage: diff --git a/scripts/selfhost-verify.sh b/scripts/selfhost-verify.sh index 120e6d2f..65be2570 100755 --- a/scripts/selfhost-verify.sh +++ b/scripts/selfhost-verify.sh @@ -56,7 +56,7 @@ command -v qemu-system-x86_64 >/dev/null || die "falta qemu-system-x86_64" # 0) Binario hammer estático (musl, crt-static) — el builder lo bootea adentro. HAMMER_BIN="target/x86_64-unknown-linux-musl/release/hammer" say "build hammer estático ($HAMMER_BIN)" -cargo build --release --target x86_64-unknown-linux-musl -p hammer-cli +cargo build --release --target x86_64-unknown-linux-musl -p takana-cli HAMMER="./$HAMMER_BIN" say "stage0 — ingerir la semilla zig (idempotente)" diff --git a/scripts/upgrade-e2e-test.sh b/scripts/upgrade-e2e-test.sh index 59daad7e..e2af2433 100755 --- a/scripts/upgrade-e2e-test.sh +++ b/scripts/upgrade-e2e-test.sh @@ -19,7 +19,7 @@ JOURNAL="$WORK/journal" mkdir -p "$STORE" "$ROOT/usr/bin" "$ROOT/etc" echo "==> compilando hammer" -cargo build -q -p hammer-cli --manifest-path "$ROOT_DIR/Cargo.toml" +cargo build -q -p takana-cli --manifest-path "$ROOT_DIR/Cargo.toml" HAMMER="$ROOT_DIR/target/debug/hammer" up() { "$HAMMER" --store "$STORE" upgrade --root "$ROOT" --state-root "$STATE" --journal "$JOURNAL" "$@"; }