b85700c538
La Card pasa a ser EL protocolo de presentación del ecosistema. Una
Mónada Nouser y un Ente Brahman son ambos "entidades que se presentan";
el consumidor (UI, broker, admin) discrimina por `kind` cuando importa,
pero todos hablan el mismo idioma.
brahman-card:
- CardKind { Ente (default), Data }. Backward-compat: Cards existentes
quedan Ente.
- DataFacet { summary, keywords, centroid, member_count, dispersion,
presentation_hint } — vista liviana para el wire. Listas grandes
(members reales, embeddings completos) se consultan al daemon dueño
bajo demanda.
- Card.kind y Card.data agregados. WireCard espeja, conversiones From
propagan ambos campos.
- Default impl actualizado.
brahman-broker:
- BrokeredCard propaga kind y data desde la Card registrada. No afecta
el matching (sigue por TypeRef + priority + pin_to); permite a
observadores discriminar sin re-query.
nouser-card:
- Depende ahora de brahman-card.
- MonadManifest::to_brahman_card() proyecta una Mónada a Card brahman:
- id, label, lineage directos.
- payload Virtual, supervision Delegate, lifecycle Daemon
(placeholder — la Mónada no se ejecuta).
- kind = Data.
- data = Some(DataFacet { summary, keywords, centroide,
member_count, entropy → dispersion, presentation_hint del Lens }).
- Test nuevo projects_to_brahman_card.
brahman-status:
- Prefijo [ente] o [data] por sesión.
- Sesiones data renderean también summary, members + dispersion,
keywords y lens hint.
Resultado: la UI ve una sola lista uniforme — no necesita saber si
mira procesos o cúmulos de datos, sólo lee el Card y se adapta por
kind. La función de presentarse es la misma para todos.
Tests: 59 (card 11, broker 15, handshake codec+tr 2 + integ 7,
card-wit 4, admin 0, nouser-card 7 +1, nouser-core 13).
cargo check --workspace: 0 errores, 0 warnings.
Próximo: Phase B-2 — bin nouser daemon que sidecarea cada Mónada como
sesión brahman, mezclándolas con los entes en brahman-status.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
3.2 KiB
Rust
90 lines
3.2 KiB
Rust
//! `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
|
|
);
|
|
if let Some(ctx) = &snap.current_context {
|
|
println!("Context: {}", ctx);
|
|
}
|
|
println!();
|
|
println!("Sessions ({}):", snap.sessions.len());
|
|
if snap.sessions.is_empty() {
|
|
println!(" (ninguna)");
|
|
} else {
|
|
for s in &snap.sessions {
|
|
let conscious_marker = if s.wit.is_some() { " 🧠" } else { "" };
|
|
let kind_marker = match s.kind {
|
|
brahman_card::CardKind::Ente => "ente",
|
|
brahman_card::CardKind::Data => "data",
|
|
};
|
|
println!(
|
|
" [{}] {} {}{} lifecycle={:?} priority={:?}",
|
|
kind_marker, s.session, s.label, conscious_marker, s.lifecycle, s.priority
|
|
);
|
|
if let Some(data) = &s.data {
|
|
if !data.summary.is_empty() {
|
|
println!(" summary: {}", data.summary);
|
|
}
|
|
if data.member_count > 0 {
|
|
println!(
|
|
" members: {} (dispersion={:.2})",
|
|
data.member_count, data.dispersion
|
|
);
|
|
}
|
|
if !data.keywords.is_empty() {
|
|
println!(" keywords: {}", data.keywords.join(", "));
|
|
}
|
|
if !data.presentation_hint.is_empty() {
|
|
println!(" lens hint: {}", data.presentation_hint);
|
|
}
|
|
}
|
|
if let Some(wit) = &s.wit {
|
|
println!(" wit: {} / {}", wit.package, wit.world);
|
|
if !wit.imports.is_empty() {
|
|
println!(" imports: {}", wit.imports.join(", "));
|
|
}
|
|
if !wit.exports.is_empty() {
|
|
println!(" exports: {}", wit.exports.join(", "));
|
|
}
|
|
}
|
|
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(())
|
|
}
|