Files
brahman/crates/apps/yahweh-shell/src/main.rs
T
Sergio 595f68e252 feat(yahweh-shell): primer módulo brahman vivo
yahweh-shell se presenta al Init brahman como módulo Widget mediante un
sidecar en thread aparte. La GUI GPUI levanta normalmente; el sidecar
mantiene la sesión brahman en paralelo, desacoplado.

Cambios:

- crates/apps/yahweh-shell/Cargo.toml: deps brahman-card, brahman-handshake,
  ulid.
- crates/apps/yahweh-shell/src/brahman_client.rs: thread con tokio
  current_thread runtime que arma una Card, llama Client::connect, y
  loop de pings cada 30s. Si el Init no está disponible, loggea y
  termina — yahweh sigue funcionando standalone.
- crates/apps/yahweh-shell/src/main.rs: brahman_client::spawn() antes
  de Application::new(). El spawn no bloquea.

Card declarada por yahweh:
- label: "brahman.ui_engine"
- lifecycle: Widget
- payload: Virtual (yahweh no se inicia desde el Init, se presenta)
- supervision: Delegate
- permissions: filesystem read-write (persiste layout.json), IPC wit-v1
- flow.input: render-data (json)
- flow.output: user-intent (json)

Validación end-to-end:
  $ ente-zero &
  $ probe                          → session=...8G, init_attached=true
  $ yahweh                         → [brahman] attached: session=...Y7

Ambos clientes (probe + yahweh sidecar) se registran en el broker del
Init en sesiones distintas. yahweh es el primer módulo "real" — no un
tester — que vive como nodo del fractal mientras corre.

Tests: 27/27 verdes. cargo check --workspace: 0 errores.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 15:08:03 +00:00

69 lines
2.3 KiB
Rust

//! Yahweh — bootstrap GPUI.
//!
//! Fase 6: además del LayoutModel, la Shell crea un `AppBus` (Entity) y se
//! lo pasa al LayoutHost. El bus circula a viewers (TextViewer,
//! ImageViewer) que se subscriben directo, y el LayoutHost forwardea los
//! eventos tipados de los explorers (FileExplorer, DatabaseExplorer)
//! traducidos a AppEvent.
mod brahman_client;
mod hot_reload;
mod layout_host;
mod layout_model;
mod managed_tree;
mod persister;
mod status_panel;
use gpui::{App, Application, Bounds, WindowBounds, WindowOptions, prelude::*, px, size};
use yahweh_bus::AppBus;
use yahweh_core::LayerConfig;
use yahweh_theme::Theme;
use crate::layout_host::LayoutHost;
use crate::layout_model::LayoutModel;
use crate::persister::Persister;
const LAYOUT_PATH: &str = "layout.json";
fn main() {
// Sidecar brahman: yahweh se presenta al Init antes de levantar GPUI.
// No bloquea: si el Init no está, el thread loggea y termina.
brahman_client::spawn();
Application::new().run(|cx: &mut App| {
Theme::install_default(cx);
let config = LayerConfig::load_or_default(LAYOUT_PATH);
let bounds = Bounds::centered(None, size(px(1300.), px(800.)), cx);
cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|_w, cx| {
let model = cx.new(|_| LayoutModel::new(config.clone()));
let bus = cx.new(|_| AppBus);
let persister = cx.new(|cx| {
Persister::new(LAYOUT_PATH.into(), model.clone(), cx)
});
// Hot-reload: notify watcher en el dir del JSON. El
// watcher debe mantenerse vivo (drop ⇒ stop), así que lo
// movemos a una static atómica vía Box::leak.
match hot_reload::spawn_watch(LAYOUT_PATH.into(), model.clone(), cx) {
Ok(watcher) => {
Box::leak(Box::new(watcher));
}
Err(e) => {
eprintln!("[hot_reload] no se pudo iniciar watcher: {}", e);
}
}
cx.new(|cx| LayoutHost::new(model, bus, persister, cx))
},
)
.unwrap();
cx.activate(true);
});
}