chore: monorepo inicial con arje + minga + yahweh absorbidos

Workspace en 4 ejes (core/modules/apps/shared):

- core/: 24 crates de arje (Init systemd-compatible: ente-card, ente-zero,
  ente-kernel, ente-bus, ente-cas, ente-soma, ente-wasm, ente-snapshot,
  ente-brain, ente-echo, ente-policy-provider, + 12 crates *-compat)
- modules/semantic_dht/: 5 crates de minga (minga-core con AST/CAS/MST,
  minga-p2p con libp2p Kad, minga-store, minga-vfs, minga-cli)
- modules/ui_engine/: 11 crates de yahweh (libs/{core,theme,bus,providers},
  widgets/{tree,splitter,tabs,tiled,container_core,text_input})
- apps/: 5 crates de yahweh (file_explorer, database_explorer, text_viewer,
  image_viewer, yahweh-shell)
- shared_wit/protocol.wit: handshake/lifecycle inicial

Cargo.toml unificado: thiserror bumped a 2 (transparente para arje), tokio
"full", paths intra-workspace de yahweh redirigidos a su nueva ubicación.

cargo check --workspace: 0 errores, 17 warnings (dead code preexistente).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-05-08 04:45:44 +00:00
commit 53dbdf0f1d
176 changed files with 34845 additions and 0 deletions
@@ -0,0 +1,12 @@
[package]
name = "yahweh-provider-fs"
version = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
description = "DataProvider de filesystem local."
[dependencies]
yahweh-core = { workspace = true }
async-trait = { workspace = true }
tokio = { workspace = true }
notify = { workspace = true }
@@ -0,0 +1,67 @@
//! Provider de filesystem local. Crate puro: cero dependencia de UI.
//! Implementa `yahweh_core::DataProvider` listando hijos de un path con
//! `std::fs::read_dir` y leyendo archivos a `Vec<u8>` via `tokio::io`.
use async_trait::async_trait;
use std::fs;
use std::io::Cursor;
use std::path::Path;
use std::pin::Pin;
use tokio::io::{AsyncRead, AsyncWrite};
use yahweh_core::{DataProvider, DisplayType, EntityNode};
pub const PROVIDER_ID: &str = "local_fs";
pub struct FileDataProvider;
#[async_trait]
impl DataProvider for FileDataProvider {
fn provider_id(&self) -> String {
PROVIDER_ID.to_string()
}
async fn list_children(&self, parent_id: Option<&str>) -> Result<Vec<EntityNode>, String> {
let path = parent_id.unwrap_or(".");
let mut children = Vec::new();
if let Ok(entries) = fs::read_dir(path) {
for entry in entries.filter_map(|e| e.ok()) {
let path = entry.path();
let name = path
.file_name()
.unwrap_or_default()
.to_string_lossy()
.into_owned();
let display_type = if path.is_dir() {
DisplayType::Folder
} else {
DisplayType::File
};
children.push(EntityNode {
id: path.to_string_lossy().into_owned(),
name,
display_type,
mime_type: None,
});
}
}
Ok(children)
}
async fn get_read_stream(
&self,
entity_id: &str,
) -> Result<Pin<Box<dyn AsyncRead + Send>>, String> {
let content = fs::read(Path::new(entity_id)).map_err(|e| e.to_string())?;
Ok(Box::pin(Cursor::new(content)))
}
async fn get_write_stream(
&self,
_entity_id: &str,
) -> Result<Pin<Box<dyn AsyncWrite + Send>>, String> {
Err("Escritura en streaming no implementada para FS".to_string())
}
}
@@ -0,0 +1,12 @@
[package]
name = "yahweh-provider-sqlite"
version = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
description = "DataProvider de SQLite (jerarquía vía parent_id)."
[dependencies]
yahweh-core = { workspace = true }
async-trait = { workspace = true }
tokio = { workspace = true }
rusqlite = { workspace = true }
@@ -0,0 +1,118 @@
//! Provider de SQLite. Crate puro: cero dependencia de UI.
//! Tabla `items(id, parent_id, name, display_type, content)` con jerarquía
//! por `parent_id NULL` = raíz.
use async_trait::async_trait;
use rusqlite::Connection;
use std::io::Cursor;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
use tokio::io::{AsyncRead, AsyncWrite};
use yahweh_core::{DataProvider, DisplayType, EntityNode};
pub const PROVIDER_ID: &str = "sqlite_db";
pub struct SqliteDataProvider {
db: Arc<Mutex<Connection>>,
}
impl SqliteDataProvider {
pub fn new(path: &str) -> Result<Self, String> {
let conn = Connection::open(path).map_err(|e| e.to_string())?;
conn.execute(
"CREATE TABLE IF NOT EXISTS items (
id TEXT PRIMARY KEY,
parent_id TEXT,
name TEXT NOT NULL,
display_type TEXT NOT NULL,
content BLOB
)",
[],
)
.map_err(|e| e.to_string())?;
// Seed mínimo si la tabla está vacía — para que el DatabaseExplorer
// tenga algo que mostrar en una primera ejecución sin pre-config.
let count: i64 = conn
.query_row("SELECT COUNT(*) FROM items", [], |row| row.get(0))
.unwrap_or(0);
if count == 0 {
let _ = conn.execute(
"INSERT INTO items (id, parent_id, name, display_type, content) VALUES \
('readme', NULL, 'README.md', 'File', ?), \
('notes', NULL, 'notes', 'Folder', NULL), \
('todo', 'notes', 'TODO.md', 'File', ?)",
rusqlite::params![
b"# Yahweh\n\nDemo readme stored in SQLite.\n",
b"- TreeView gen\xC3\xA9rico\n- containers swappables\n- layout JSON\n",
],
);
}
Ok(Self {
db: Arc::new(Mutex::new(conn)),
})
}
}
#[async_trait]
impl DataProvider for SqliteDataProvider {
fn provider_id(&self) -> String {
PROVIDER_ID.to_string()
}
async fn list_children(&self, parent_id: Option<&str>) -> Result<Vec<EntityNode>, String> {
let db = self.db.lock().unwrap();
let mut stmt = db
.prepare("SELECT id, name, display_type FROM items WHERE parent_id IS ?")
.map_err(|e| e.to_string())?;
let rows = stmt
.query_map([parent_id], |row| {
let display_type_str: String = row.get(2)?;
let display_type = match display_type_str.as_str() {
"Folder" => DisplayType::Folder,
"Stream" => DisplayType::Stream,
_ => DisplayType::File,
};
Ok(EntityNode {
id: row.get(0)?,
name: row.get(1)?,
display_type,
mime_type: None,
})
})
.map_err(|e| e.to_string())?;
let mut children = Vec::new();
for row in rows {
children.push(row.map_err(|e| e.to_string())?);
}
Ok(children)
}
async fn get_read_stream(
&self,
entity_id: &str,
) -> Result<Pin<Box<dyn AsyncRead + Send>>, String> {
let db = self.db.lock().unwrap();
let content: Vec<u8> = db
.query_row(
"SELECT content FROM items WHERE id = ?",
[entity_id],
|row| row.get(0),
)
.map_err(|e| e.to_string())?;
Ok(Box::pin(Cursor::new(content)))
}
async fn get_write_stream(
&self,
_entity_id: &str,
) -> Result<Pin<Box<dyn AsyncWrite + Send>>, String> {
Err("Escritura en streaming no implementada para SQLite (todavía)".to_string())
}
}