feat: segundo módulo (nakui) + admin API + brahman-status
Dos cosas en una sesión, en el orden discutido:
(1) Segundo módulo brahman vivo: nakui-core
- crates/modules/nakui/core/Cargo.toml: deps brahman-card,
brahman-sidecar, ulid.
- crates/modules/nakui/core/src/bin/nakui.rs: brahman_card_for_nakui()
construye una Card como Lifecycle::Daemon, Supervision::Restart,
flow.input "command" (json) + flow.output "report" (json). El
cmd_run llama brahman_sidecar::spawn antes de levantar el server
de nakui.
(2) crates/shared/brahman-sidecar (estrena crates/shared/)
Boilerplate del sidecar extraído (DRY): el thread con tokio current
thread runtime, conexión vía Client::connect, ping loop. Yahweh y
nakui ahora consumen este crate. API:
- spawn(card) fire-and-forget
- spawn_with_handle(config) con JoinHandle
Example "presence" útil para demos: módulo dummy con label tomado
del primer arg que se queda vivo hasta SIGTERM.
(3) crates/core/brahman-admin: observabilidad del broker
Socket Unix paralelo en \$BRAHMAN_ADMIN_SOCKET (default
\$XDG_RUNTIME_DIR/brahman-admin.sock). Cada conexión recibe un
StatusSnapshot JSON line-delimited y se cierra. Compatible con nc/socat.
- StatusSnapshot { server, protocol, init_attached, sessions, matches }
- server::AdminServer
- client::query(path)
- example "brahman-status" CLI
(4) Wiring de ente-zero
En primordial_loop, junto al handshake server, ahora también levanta
AdminServer con misma política de degradación grácil.
(5) brahman-broker: BrokeredCard ahora incluye lifecycle. Endpoint y
Match derivan Serialize/Deserialize. Nuevo método cards() expone
iterador de BrokeredCard para que el admin pueda construir snapshots.
(6) brahman-card: re-export pub use ulid::* para que módulos no
necesiten depender de ulid directamente.
(7) yahweh-shell migrado al sidecar compartido. Su brahman_client.rs
pasa de 96 a 53 líneas: sólo declara la Card, delega el spawn.
Demo end-to-end:
$ ente-zero &
$ presence demo.producer &
$ presence demo.consumer &
$ brahman-status
Init: server=0.1.0 protocol=0.1.0 attached=true
Sessions (2):
01KR42TY1J... demo.producer lifecycle=Daemon priority=Normal
01KR42TY1K... demo.consumer lifecycle=Daemon priority=Normal
Matches (2):
demo.producer.in ← demo.consumer.out via Exact
demo.consumer.in ← demo.producer.out via Exact
El broker matchea bidireccional por tipo. El admin lo expone.
Tests: 27/27. cargo check --workspace: 0 errores.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
//! `brahman-status` — CLI para inspeccionar el estado del Init.
|
||||
//!
|
||||
//! Conecta al socket admin (default `$XDG_RUNTIME_DIR/brahman-admin.sock`,
|
||||
//! override con `$BRAHMAN_ADMIN_SOCKET`), recibe el snapshot, y lo imprime.
|
||||
|
||||
use brahman_admin::{client, transport};
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
let path = transport::default_socket_path();
|
||||
let snap = client::query(&path).await?;
|
||||
|
||||
println!(
|
||||
"Init: server={} protocol={} attached={}",
|
||||
snap.server_version, snap.protocol_version, snap.init_attached
|
||||
);
|
||||
println!();
|
||||
println!("Sessions ({}):", snap.sessions.len());
|
||||
if snap.sessions.is_empty() {
|
||||
println!(" (ninguna)");
|
||||
} else {
|
||||
for s in &snap.sessions {
|
||||
println!(
|
||||
" {} {} lifecycle={:?} priority={:?}",
|
||||
s.session, s.label, s.lifecycle, s.priority
|
||||
);
|
||||
for f in &s.inputs {
|
||||
println!(" in {}: {:?}", f.name, f.ty);
|
||||
}
|
||||
for f in &s.outputs {
|
||||
println!(" out {}: {:?}", f.name, f.ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
println!();
|
||||
println!("Matches ({}):", snap.matches.len());
|
||||
if snap.matches.is_empty() {
|
||||
println!(" (ninguno)");
|
||||
} else {
|
||||
for m in &snap.matches {
|
||||
let pin_marker = if m.pinned { "📌" } else { " " };
|
||||
println!(
|
||||
" {} {}.{} ← {}.{} via {:?}",
|
||||
pin_marker,
|
||||
m.consumer_label,
|
||||
m.consumer.flow_name,
|
||||
m.producer_label,
|
||||
m.producer.flow_name,
|
||||
m.via
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user