refactor(naming): A1 — ente→arje, vista→revista, pluma→fana
Rename batch de la Fase A del PLAN_MACRO: - 25 crates ente-* → arje-* (protocol/init/runtime/compat). El linaje arje (init Linux) queda con prefijo coherente. - vista → revista (revista-core + revista-web). - pluma → fana (fana-md + fana-md-reader-web). fana absorbe el linaje markdown de pluma; será el writer DAG editor (prioridad alta). Cambios: - git mv de 29 crate dirs + 2 SDDs - package/lib/bin names + path refs + imports .rs reescritos - workspace Cargo.toml + comentarios de sección - SDDs de init/runtime/compat/protocol actualizados a arje- - SDD de revista + SDD de fana (reescrito: writer DAG editor) - docs/STATUS.md, ROADMAP.md, PLAN_MACRO.md, arje-boot.md, arje-replace-systemd.md actualizados - docs/changelog/akasha.md → chasqui.md scripts/rename-fase-a.py idempotente (--dry-run soportado). cargo check --workspace verde. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "akasha-card"
|
||||
name = "chasqui-card"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
@@ -1,4 +1,4 @@
|
||||
//! `akasha-card` — manifiesto de Mónada.
|
||||
//! `chasqui-card` — manifiesto de Mónada.
|
||||
//!
|
||||
//! Una **Mónada** es una agrupación semántica de archivos: el archivo
|
||||
//! físico no se mueve, pero su pertenencia se modela por un objeto
|
||||
@@ -10,7 +10,7 @@
|
||||
//!
|
||||
//! Diferencia con `brahman-card::Card`:
|
||||
//!
|
||||
//! | brahman::Card | akasha::MonadManifest |
|
||||
//! | brahman::Card | chasqui::MonadManifest |
|
||||
//! |-------------------------------------|-------------------------------|
|
||||
//! | Describe una **entidad runtime** | Describe una **agrupación** |
|
||||
//! | Tiene `payload`/`soma`/`supervision`| No tiene proceso detrás |
|
||||
@@ -18,7 +18,7 @@
|
||||
//! | Fluye por handshake/postcard | Fluye por queries del backend |
|
||||
//!
|
||||
//! Este crate sólo define los tipos. La lógica de scan, cluster,
|
||||
//! attraction vive en `akasha-core`.
|
||||
//! attraction vive en `chasqui-core`.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
@@ -1,12 +1,12 @@
|
||||
//! Wire types para consultar al daemon `akasha` por sus Mónadas.
|
||||
//! Wire types para consultar al daemon `chasqui` por sus Mónadas.
|
||||
//!
|
||||
//! El daemon expone un Unix socket (cuyo path se publica en
|
||||
//! `Card.service_socket` y se descubre vía broker MatchEvent). Cada
|
||||
//! conexión es single-shot: una request JSON terminada en `\n`,
|
||||
//! una response JSON terminada en `\n`, cierre.
|
||||
//!
|
||||
//! Mismo patrón que `akasha-nous` (mock/real ↔ akasha-core), reusado
|
||||
//! ahora para que la UI (`akasha-explorer`) descubra y consulte al
|
||||
//! Mismo patrón que `chasqui-nous` (mock/real ↔ chasqui-core), reusado
|
||||
//! ahora para que la UI (`chasqui-explorer`) descubra y consulte al
|
||||
//! daemon sin hardcodear sockets ni pasar por brahman-admin.
|
||||
//!
|
||||
//! ## Contrato
|
||||
@@ -118,7 +118,7 @@ impl MonadView {
|
||||
|
||||
/// Error de protocolo retornado en lugar de la response normal.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Error)]
|
||||
#[error("akasha-engine: {error}")]
|
||||
#[error("chasqui-engine: {error}")]
|
||||
pub struct ErrorResponse {
|
||||
pub error: String,
|
||||
}
|
||||
@@ -135,7 +135,7 @@ pub mod transport {
|
||||
pub const SOCKET_ENV: &str = "NOUSER_ENGINE_SOCKET";
|
||||
|
||||
/// Nombre por defecto del socket.
|
||||
pub const SOCKET_NAME: &str = "akasha-engine.sock";
|
||||
pub const SOCKET_NAME: &str = "chasqui-engine.sock";
|
||||
|
||||
/// Ruta canónica al socket del daemon. Honra `NOUSER_ENGINE_SOCKET`
|
||||
/// si está set, sino arma sobre `$XDG_RUNTIME_DIR` (con fallback
|
||||
@@ -154,7 +154,7 @@ pub mod transport {
|
||||
// =====================================================================
|
||||
// Cliente blocking — vive con los wire types para que un consumer
|
||||
// (UI, CLI, otro módulo) pueda hablar con el daemon importando sólo
|
||||
// `akasha-card`, sin arrastrar `akasha-core` (notify/walkdir/sled/blake3).
|
||||
// `chasqui-card`, sin arrastrar `chasqui-core` (notify/walkdir/sled/blake3).
|
||||
// =====================================================================
|
||||
|
||||
/// Cliente síncrono para el query socket del daemon. Sólo Unix (el
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "akasha-core"
|
||||
name = "chasqui-core"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
@@ -9,8 +9,8 @@ publish.workspace = true
|
||||
description = "Nouser — explorador de Mónadas: scanner, clustering determinista, DB en memoria."
|
||||
|
||||
[dependencies]
|
||||
akasha-card = { path = "../card" }
|
||||
akasha-nous = { path = "../nous" }
|
||||
chasqui-card = { path = "../card" }
|
||||
chasqui-nous = { path = "../nous" }
|
||||
shuma-discern = { path = "../../shuma/shuma-discern" }
|
||||
brahman-card = { path = "../../../protocol/brahman-card" }
|
||||
brahman-handshake = { path = "../../../protocol/brahman-handshake" }
|
||||
@@ -29,5 +29,5 @@ notify = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "akasha"
|
||||
name = "chasqui"
|
||||
path = "src/bin/nouser.rs"
|
||||
+36
-36
@@ -1,4 +1,4 @@
|
||||
//! `akasha` CLI — explorador de Mónadas.
|
||||
//! `chasqui` CLI — explorador de Mónadas.
|
||||
//!
|
||||
//! Subcomandos:
|
||||
//!
|
||||
@@ -13,14 +13,14 @@
|
||||
use std::path::PathBuf;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use akasha_core::{
|
||||
use chasqui_core::{
|
||||
cluster, db, embed,
|
||||
scanner::{self, ScanConfig},
|
||||
};
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
let prog = args.first().cloned().unwrap_or_else(|| "akasha".into());
|
||||
let prog = args.first().cloned().unwrap_or_else(|| "chasqui".into());
|
||||
let sub = match args.get(1).map(String::as_str) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
@@ -41,7 +41,7 @@ fn main() -> ExitCode {
|
||||
return ExitCode::SUCCESS;
|
||||
}
|
||||
other => {
|
||||
eprintln!("akasha: comando desconocido '{other}'");
|
||||
eprintln!("chasqui: comando desconocido '{other}'");
|
||||
print_usage(&prog);
|
||||
return ExitCode::from(2);
|
||||
}
|
||||
@@ -50,7 +50,7 @@ fn main() -> ExitCode {
|
||||
match result {
|
||||
Ok(()) => ExitCode::SUCCESS,
|
||||
Err(e) => {
|
||||
eprintln!("akasha: {e}");
|
||||
eprintln!("chasqui: {e}");
|
||||
ExitCode::from(1)
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,7 @@ fn cmd_daemon(args: &[String]) -> Cmd {
|
||||
|
||||
// 1. Decidir el path del query socket ANTES de armar el engine
|
||||
// Card (porque viaja como service_socket en la Card).
|
||||
let query_socket = akasha_card::query::transport::default_socket_path();
|
||||
let query_socket = chasqui_card::query::transport::default_socket_path();
|
||||
|
||||
// 2. Engine como Ente. Declara service_socket + flow.output para
|
||||
// que el broker pueda emitir MatchEvent::Available a consumers
|
||||
@@ -190,7 +190,7 @@ fn cmd_daemon(args: &[String]) -> Cmd {
|
||||
let engine_id = engine_card.id;
|
||||
let engine_label = engine_card.label.clone();
|
||||
eprintln!(
|
||||
"akasha daemon: publicando engine '{}' (kind=Ente, id={}, socket={})",
|
||||
"chasqui daemon: publicando engine '{}' (kind=Ente, id={}, socket={})",
|
||||
engine_label,
|
||||
engine_id,
|
||||
query_socket.display()
|
||||
@@ -227,7 +227,7 @@ fn cmd_daemon(args: &[String]) -> Cmd {
|
||||
hydrated += 1;
|
||||
}
|
||||
eprintln!(
|
||||
"akasha daemon: hidratadas {} mónadas previas{} en O(1)",
|
||||
"chasqui daemon: hidratadas {} mónadas previas{} en O(1)",
|
||||
hydrated,
|
||||
if skipped_model > 0 {
|
||||
format!(" ({} dropeadas por centroid_model distinto)", skipped_model)
|
||||
@@ -245,7 +245,7 @@ fn cmd_daemon(args: &[String]) -> Cmd {
|
||||
let monads = cluster::by_directory_hydrated(&files, min_files(), Some(&db));
|
||||
let scanned_count = monads.len();
|
||||
eprintln!(
|
||||
"akasha daemon: re-scan {} archivos en {} → {} mónadas",
|
||||
"chasqui daemon: re-scan {} archivos en {} → {} mónadas",
|
||||
n_files,
|
||||
dir.display(),
|
||||
scanned_count
|
||||
@@ -276,7 +276,7 @@ fn cmd_daemon(args: &[String]) -> Cmd {
|
||||
db.replace_monads(monads);
|
||||
|
||||
eprintln!(
|
||||
"akasha daemon: 1 ente + {} mónadas vivas ({} nuevas vs hidratación)",
|
||||
"chasqui daemon: 1 ente + {} mónadas vivas ({} nuevas vs hidratación)",
|
||||
scanned_count, newly_spawned
|
||||
);
|
||||
|
||||
@@ -285,8 +285,8 @@ fn cmd_daemon(args: &[String]) -> Cmd {
|
||||
// Si el bind falla, seguimos sin él — la UI degrada a "no
|
||||
// alcanzable" pero el daemon sigue procesando cambios.
|
||||
let db_shared = std::sync::Arc::new(std::sync::Mutex::new(db));
|
||||
let _query_listener = match akasha_core::engine_socket::spawn_listener(
|
||||
akasha_core::engine_socket::ListenerConfig {
|
||||
let _query_listener = match chasqui_core::engine_socket::spawn_listener(
|
||||
chasqui_core::engine_socket::ListenerConfig {
|
||||
socket_path: query_socket.clone(),
|
||||
engine_id,
|
||||
engine_label: engine_label.clone(),
|
||||
@@ -296,14 +296,14 @@ fn cmd_daemon(args: &[String]) -> Cmd {
|
||||
) {
|
||||
Ok(h) => {
|
||||
eprintln!(
|
||||
"akasha daemon: query socket activo en {} (proto: akasha_card::query)",
|
||||
"chasqui daemon: query socket activo en {} (proto: chasqui_card::query)",
|
||||
query_socket.display()
|
||||
);
|
||||
Some(h)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"akasha daemon: query socket NO disponible ({e}) — explorer no podrá consultar"
|
||||
"chasqui daemon: query socket NO disponible ({e}) — explorer no podrá consultar"
|
||||
);
|
||||
None
|
||||
}
|
||||
@@ -322,14 +322,14 @@ fn cmd_daemon(args: &[String]) -> Cmd {
|
||||
) {
|
||||
Ok(w) => {
|
||||
eprintln!(
|
||||
"akasha daemon: watcher activo en {} (debounce 150ms, re-publish on) — Ctrl-C para terminar.",
|
||||
"chasqui daemon: watcher activo en {} (debounce 150ms, re-publish on) — Ctrl-C para terminar.",
|
||||
dir.display()
|
||||
);
|
||||
Some(w)
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!(
|
||||
"akasha daemon: watcher deshabilitado ({e}) — Ctrl-C para terminar."
|
||||
"chasqui daemon: watcher deshabilitado ({e}) — Ctrl-C para terminar."
|
||||
);
|
||||
None
|
||||
}
|
||||
@@ -385,7 +385,7 @@ fn spawn_fs_watcher(
|
||||
// Dispatcher: notify → filtro → canal de paths.
|
||||
let dispatch_dir = dir.clone();
|
||||
std::thread::Builder::new()
|
||||
.name("akasha-watcher-dispatch".into())
|
||||
.name("chasqui-watcher-dispatch".into())
|
||||
.spawn(move || {
|
||||
for res in notify_rx {
|
||||
let event = match res {
|
||||
@@ -416,7 +416,7 @@ fn spawn_fs_watcher(
|
||||
// Coordinator: debounce + batch dispatch.
|
||||
let coord_dir = dir;
|
||||
std::thread::Builder::new()
|
||||
.name("akasha-watcher-coord".into())
|
||||
.name("chasqui-watcher-coord".into())
|
||||
.spawn(move || {
|
||||
let debounce = std::time::Duration::from_millis(WATCHER_DEBOUNCE_MS);
|
||||
let mut pending: std::collections::HashMap<
|
||||
@@ -494,7 +494,7 @@ fn process_change_batch(
|
||||
}
|
||||
};
|
||||
|
||||
let prior_monads: Vec<akasha_card::MonadManifest> = db_lock.monads().cloned().collect();
|
||||
let prior_monads: Vec<chasqui_card::MonadManifest> = db_lock.monads().cloned().collect();
|
||||
let prior_ref: &db::MonadDb = &db_lock;
|
||||
let monads = cluster::by_directory_hydrated(&files, min_files(), Some(prior_ref));
|
||||
|
||||
@@ -601,8 +601,8 @@ fn cmd_attract(args: &[String]) -> Cmd {
|
||||
.and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
|
||||
.map(|d| d.as_millis() as u64)
|
||||
.unwrap_or(0);
|
||||
let target = akasha_card::FileEntry {
|
||||
id: akasha_card::FileId::from(akasha_card::ulid::Ulid::new()),
|
||||
let target = chasqui_card::FileEntry {
|
||||
id: chasqui_card::FileId::from(chasqui_card::ulid::Ulid::new()),
|
||||
path: file_path.clone(),
|
||||
content_hash: None,
|
||||
size: metadata.len(),
|
||||
@@ -630,7 +630,7 @@ fn cmd_attract(args: &[String]) -> Cmd {
|
||||
// Filtramos Mónadas cuyo centroid_model NO matchee. Mezclar
|
||||
// 32-d con 384-d daría scores sin sentido (diferente semántica
|
||||
// y cosine no compara cross-modelo).
|
||||
let mut ranked: Vec<(&akasha_card::MonadManifest, f32)> = db
|
||||
let mut ranked: Vec<(&chasqui_card::MonadManifest, f32)> = db
|
||||
.monads()
|
||||
.filter(|m| !m.centroid.is_empty())
|
||||
.filter(|m| match &m.centroid_model {
|
||||
@@ -700,7 +700,7 @@ fn cmd_attract(args: &[String]) -> Cmd {
|
||||
/// Devuelve `(embedding, model_id)` — el caller necesita ambos para
|
||||
/// comparar contra centroides taggeados con su mismo `centroid_model`.
|
||||
fn remote_embed(
|
||||
file: &akasha_card::FileEntry,
|
||||
file: &chasqui_card::FileEntry,
|
||||
) -> Result<(Vec<f32>, String), Box<dyn std::error::Error>> {
|
||||
if let Ok(explicit) = std::env::var("NOUSER_NOUS_SOCKET") {
|
||||
let sock = std::path::PathBuf::from(explicit);
|
||||
@@ -708,9 +708,9 @@ fn remote_embed(
|
||||
}
|
||||
|
||||
let consumer = brahman_sidecar::build_consumer_card(
|
||||
"akasha.attract-cli",
|
||||
akasha_nous::FLOW_EMBED_RESULT,
|
||||
akasha_nous::FLOW_TYPE_NAME,
|
||||
"chasqui.attract-cli",
|
||||
chasqui_nous::FLOW_EMBED_RESULT,
|
||||
chasqui_nous::FLOW_TYPE_NAME,
|
||||
);
|
||||
let producer_sock = brahman_sidecar::await_provider_blocking(
|
||||
consumer,
|
||||
@@ -719,12 +719,12 @@ fn remote_embed(
|
||||
embed_via(&producer_sock, file)
|
||||
}
|
||||
|
||||
/// RPC blocking contra un socket akasha-nous concreto. Devuelve
|
||||
/// RPC blocking contra un socket chasqui-nous concreto. Devuelve
|
||||
/// `(embedding, model_id)` — el `model_id` viaja en la response y
|
||||
/// permite al caller saber qué centroides son comparables.
|
||||
fn embed_via(
|
||||
sock_path: &std::path::Path,
|
||||
file: &akasha_card::FileEntry,
|
||||
file: &chasqui_card::FileEntry,
|
||||
) -> Result<(Vec<f32>, String), Box<dyn std::error::Error>> {
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::os::unix::net::UnixStream;
|
||||
@@ -734,9 +734,9 @@ fn embed_via(
|
||||
}
|
||||
|
||||
let mut stream = UnixStream::connect(sock_path)?;
|
||||
let req = akasha_nous::EmbedRequest {
|
||||
kind: akasha_nous::RequestKind::EmbedFile,
|
||||
payload: serde_json::to_value(akasha_nous::EmbedFilePayload {
|
||||
let req = chasqui_nous::EmbedRequest {
|
||||
kind: chasqui_nous::RequestKind::EmbedFile,
|
||||
payload: serde_json::to_value(chasqui_nous::EmbedFilePayload {
|
||||
path: file.path.display().to_string(),
|
||||
extension: file.extension.clone(),
|
||||
size: file.size,
|
||||
@@ -752,14 +752,14 @@ fn embed_via(
|
||||
let mut response = String::new();
|
||||
reader.read_line(&mut response)?;
|
||||
if response.is_empty() {
|
||||
return Err("akasha-nous cerró sin respuesta".into());
|
||||
return Err("chasqui-nous cerró sin respuesta".into());
|
||||
}
|
||||
|
||||
if let Ok(resp) = serde_json::from_str::<akasha_nous::EmbedResponse>(&response) {
|
||||
if let Ok(resp) = serde_json::from_str::<chasqui_nous::EmbedResponse>(&response) {
|
||||
return Ok((resp.embedding, resp.model));
|
||||
}
|
||||
let err: akasha_nous::ErrorResponse = serde_json::from_str(&response)?;
|
||||
Err(format!("akasha-nous: {}", err.error).into())
|
||||
let err: chasqui_nous::ErrorResponse = serde_json::from_str(&response)?;
|
||||
Err(format!("chasqui-nous: {}", err.error).into())
|
||||
}
|
||||
|
||||
/// Card del propio engine (kind=Ente). Es el "ser" que produce y
|
||||
@@ -771,7 +771,7 @@ fn embed_via(
|
||||
/// brahman-admin.
|
||||
fn build_engine_card(service_socket: std::path::PathBuf) -> brahman_card::Card {
|
||||
use brahman_card::{Card, CardKind, Flow, Flows, Lifecycle, Payload, Priority, Supervision, TypeRef};
|
||||
use akasha_card::query::{FLOW_MONAD_LIST, FLOW_TYPE_NAME};
|
||||
use chasqui_card::query::{FLOW_MONAD_LIST, FLOW_TYPE_NAME};
|
||||
|
||||
Card {
|
||||
payload: Payload::Virtual,
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use akasha_card::{FileEntry, Lens, MonadManifest};
|
||||
use chasqui_card::{FileEntry, Lens, MonadManifest};
|
||||
|
||||
use crate::embed;
|
||||
|
||||
@@ -236,7 +236,7 @@ fn shannon_entropy_normalized(files: &[&FileEntry]) -> f32 {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use akasha_card::FileId;
|
||||
use chasqui_card::FileId;
|
||||
use std::path::PathBuf;
|
||||
use ulid::Ulid;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::Path;
|
||||
|
||||
use akasha_card::{FileEntry, FileId, MonadId, MonadManifest};
|
||||
use chasqui_card::{FileEntry, FileId, MonadId, MonadManifest};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@@ -188,7 +188,7 @@ fn decode_key(k: &[u8]) -> Result<ulid::Ulid, MonadDbError> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use akasha_card::Lens;
|
||||
use chasqui_card::Lens;
|
||||
use ulid::Ulid;
|
||||
|
||||
fn mk_file(path: &str) -> FileEntry {
|
||||
@@ -27,7 +27,7 @@
|
||||
//! - Dirs distintos + misma ext → similitud ~ 0.5.
|
||||
//! - Sin parecido → similitud < 0.3.
|
||||
|
||||
use akasha_card::{FileEntry, MonadId, MonadManifest};
|
||||
use chasqui_card::{FileEntry, MonadId, MonadManifest};
|
||||
|
||||
/// Dimensión del vector embedding.
|
||||
pub const EMBED_DIM: usize = 32;
|
||||
@@ -37,7 +37,7 @@ pub const EMBED_DIM: usize = 32;
|
||||
/// este string contra el suyo antes de hacer cosine similarity.
|
||||
/// Mezclar centroides de distinto MODEL_ID corrompe scores
|
||||
/// silenciosamente (dimensiones distintas, semántica distinta).
|
||||
pub const MODEL_ID: &str = "akasha-pseudo-32d";
|
||||
pub const MODEL_ID: &str = "chasqui-pseudo-32d";
|
||||
|
||||
/// Computa el embedding de un archivo. Determinístico: misma input
|
||||
/// → mismo vector. El vector queda L2-normalizado.
|
||||
@@ -185,7 +185,7 @@ pub const DEFAULT_ATTRACTION_THRESHOLD: f32 = 0.7;
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use akasha_card::FileId;
|
||||
use chasqui_card::FileId;
|
||||
use std::path::PathBuf;
|
||||
use ulid::Ulid;
|
||||
|
||||
+14
-14
@@ -1,13 +1,13 @@
|
||||
//! Listener Unix-socket que sirve [`akasha_card::query::QueryRequest`].
|
||||
//! Listener Unix-socket que sirve [`chasqui_card::query::QueryRequest`].
|
||||
//!
|
||||
//! El daemon `akasha` lo monta para que cualquier consumer (UI, CLI,
|
||||
//! El daemon `chasqui` lo monta para que cualquier consumer (UI, CLI,
|
||||
//! otro módulo) pueda preguntarle por sus Mónadas sin pasar por
|
||||
//! brahman-admin. El path del socket viaja en el `Card.service_socket`
|
||||
//! del engine; el broker brahman lo enseña vía MatchEvent::Available
|
||||
//! cuando un consumer declara `flow.input = monad-list:json`.
|
||||
//!
|
||||
//! Wire: line-delimited JSON, single-shot por conexión. Mismo patrón
|
||||
//! que `akasha-nous` (mock/real ↔ akasha-core), reutilizado.
|
||||
//! que `chasqui-nous` (mock/real ↔ chasqui-core), reutilizado.
|
||||
//!
|
||||
//! Threading: un thread dedicado, blocking I/O. No vale la pena traer
|
||||
//! tokio acá — la frecuencia esperada es muy baja (UI poll cada 2s)
|
||||
@@ -18,10 +18,10 @@ use std::os::unix::net::{UnixListener, UnixStream};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use akasha_card::query::{
|
||||
use chasqui_card::query::{
|
||||
EngineInfo, ErrorResponse, ListMonadsResponse, MonadView, QueryRequest,
|
||||
};
|
||||
use akasha_card::ulid::Ulid;
|
||||
use chasqui_card::ulid::Ulid;
|
||||
|
||||
use crate::db::MonadDb;
|
||||
|
||||
@@ -54,7 +54,7 @@ pub fn spawn_listener(
|
||||
let listener = UnixListener::bind(&config.socket_path)?;
|
||||
|
||||
let handle = std::thread::Builder::new()
|
||||
.name("akasha-engine-listener".into())
|
||||
.name("chasqui-engine-listener".into())
|
||||
.spawn(move || {
|
||||
for conn in listener.incoming() {
|
||||
match conn {
|
||||
@@ -126,17 +126,17 @@ fn encode_error(msg: String) -> String {
|
||||
serde_json::to_string(&err).unwrap_or_else(|_| "{\"error\":\"encode\"}".into())
|
||||
}
|
||||
|
||||
// El cliente blocking vive en `akasha_card::query::client` — junto a
|
||||
// El cliente blocking vive en `chasqui_card::query::client` — junto a
|
||||
// los wire types — para que un consumer pueda hablar con el daemon
|
||||
// importando sólo `akasha-card`, sin arrastrar el peso de
|
||||
// `akasha-core` (scanner / db / sled / notify / walkdir / blake3).
|
||||
// importando sólo `chasqui-card`, sin arrastrar el peso de
|
||||
// `chasqui-core` (scanner / db / sled / notify / walkdir / blake3).
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::db::MonadDb;
|
||||
use akasha_card::query::client as query_client;
|
||||
use akasha_card::MonadManifest;
|
||||
use chasqui_card::query::client as query_client;
|
||||
use chasqui_card::MonadManifest;
|
||||
use std::time::Duration;
|
||||
|
||||
fn fresh_socket_path(name: &str) -> PathBuf {
|
||||
@@ -147,7 +147,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn list_monads_roundtrip_empty() {
|
||||
let socket = fresh_socket_path("akasha-engine-test");
|
||||
let socket = fresh_socket_path("chasqui-engine-test");
|
||||
let db = Arc::new(Mutex::new(MonadDb::new()));
|
||||
let engine_id = Ulid::new();
|
||||
let _h = spawn_listener(
|
||||
@@ -178,7 +178,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn list_monads_returns_views() {
|
||||
let socket = fresh_socket_path("akasha-engine-test-views");
|
||||
let socket = fresh_socket_path("chasqui-engine-test-views");
|
||||
let db = Arc::new(Mutex::new(MonadDb::new()));
|
||||
let m1 = MonadManifest::new("alpha");
|
||||
let m2 = MonadManifest::new("beta");
|
||||
@@ -209,7 +209,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn invalid_request_returns_error_response() {
|
||||
let socket = fresh_socket_path("akasha-engine-test-bad");
|
||||
let socket = fresh_socket_path("chasqui-engine-test-bad");
|
||||
let db = Arc::new(Mutex::new(MonadDb::new()));
|
||||
let _h = spawn_listener(
|
||||
ListenerConfig {
|
||||
@@ -1,4 +1,4 @@
|
||||
//! `akasha-core` — el explorador de Mónadas.
|
||||
//! `chasqui-core` — el explorador de Mónadas.
|
||||
//!
|
||||
//! Implementa la pipeline determinista descrita en el diseño de Kairos:
|
||||
//!
|
||||
@@ -31,4 +31,4 @@ pub mod embed;
|
||||
pub mod engine_socket;
|
||||
pub mod scanner;
|
||||
|
||||
pub use akasha_card::*;
|
||||
pub use chasqui_card::*;
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
use akasha_card::{FileEntry, FileId};
|
||||
use chasqui_card::{FileEntry, FileId};
|
||||
use thiserror::Error;
|
||||
use ulid::Ulid;
|
||||
use walkdir::WalkDir;
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "akasha-nous-mock"
|
||||
name = "chasqui-nous-mock"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
@@ -11,9 +11,9 @@ description = "Nouser — Nous mock determinístico: implementa el contrato nous
|
||||
[dependencies]
|
||||
brahman-card = { path = "../../../protocol/brahman-card" }
|
||||
brahman-sidecar = { path = "../../../protocol/brahman-sidecar" }
|
||||
akasha-card = { path = "../card" }
|
||||
akasha-core = { path = "../core" }
|
||||
akasha-nous = { path = "../nous" }
|
||||
chasqui-card = { path = "../card" }
|
||||
chasqui-core = { path = "../core" }
|
||||
chasqui-nous = { path = "../nous" }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
@@ -21,5 +21,5 @@ tracing-subscriber = { workspace = true }
|
||||
ulid = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "akasha-nous-mock"
|
||||
name = "chasqui-nous-mock"
|
||||
path = "src/main.rs"
|
||||
+13
-13
@@ -1,7 +1,7 @@
|
||||
//! `akasha-nous-mock` — proveedor de embeddings determinista (sin LLM).
|
||||
//! `chasqui-nous-mock` — proveedor de embeddings determinista (sin LLM).
|
||||
//!
|
||||
//! Implementa el contrato `akasha-nous` usando los pseudo-embeddings
|
||||
//! de Phase C (`akasha_core::embed`). Sirve como:
|
||||
//! Implementa el contrato `chasqui-nous` usando los pseudo-embeddings
|
||||
//! de Phase C (`chasqui_core::embed`). Sirve como:
|
||||
//!
|
||||
//! - **Mock para tests**: en `BRAHMAN_BROKER_CONTEXT=test`, el
|
||||
//! `priority_offset` per-contexto declarado en su Card lo prioriza
|
||||
@@ -16,7 +16,7 @@
|
||||
//! `priority_contexts.test = { priority_offset: +1 }` lo prioriza
|
||||
//! cuando el broker corre bajo contexto test.
|
||||
//! 2. Bind del Unix socket en `$NOUSER_NOUS_SOCKET` (default
|
||||
//! `$XDG_RUNTIME_DIR/akasha-nous.sock`).
|
||||
//! `$XDG_RUNTIME_DIR/chasqui-nous.sock`).
|
||||
//! 3. Loop: accept → read line JSON → process → write line JSON → close.
|
||||
//! 4. Cada request se loggea (info) — útil para verificar que el
|
||||
//! consumidor está usando este proveedor.
|
||||
@@ -29,9 +29,9 @@ use brahman_card::{
|
||||
ulid::Ulid, Card, CardKind, ContextBias, Flow, Flows, Lifecycle, Payload, Priority,
|
||||
Supervision, TypeRef,
|
||||
};
|
||||
use akasha_card::FileEntry;
|
||||
use akasha_core::embed;
|
||||
use akasha_nous::{
|
||||
use chasqui_card::FileEntry;
|
||||
use chasqui_core::embed;
|
||||
use chasqui_nous::{
|
||||
transport, EmbedFilePayload, EmbedRequest, EmbedResponse, EmbedTextPayload, ErrorResponse,
|
||||
PingResponse, RequestKind, FLOW_EMBED_REQUEST, FLOW_EMBED_RESULT, FLOW_TYPE_NAME,
|
||||
};
|
||||
@@ -39,11 +39,11 @@ use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||
use tokio::net::{UnixListener, UnixStream};
|
||||
use tracing::{info, warn};
|
||||
|
||||
/// El mock implementa el MISMO algoritmo que `akasha_core::embed`,
|
||||
/// El mock implementa el MISMO algoritmo que `chasqui_core::embed`,
|
||||
/// así que reportamos el mismo `MODEL_ID` que él. De otro modo el
|
||||
/// consumer filtraría las Mónadas como "modelo distinto" y los
|
||||
/// scores quedarían vacíos.
|
||||
const MODEL_ID: &str = akasha_core::embed::MODEL_ID;
|
||||
const MODEL_ID: &str = chasqui_core::embed::MODEL_ID;
|
||||
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
@@ -60,7 +60,7 @@ async fn main() -> std::io::Result<()> {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
let listener = UnixListener::bind(&sock_path)?;
|
||||
info!(socket = %sock_path.display(), "akasha-nous-mock escuchando");
|
||||
info!(socket = %sock_path.display(), "chasqui-nous-mock escuchando");
|
||||
|
||||
// 2. Sidecar al brahman-init con la Card que declara el socket.
|
||||
let card = build_card(sock_path.clone());
|
||||
@@ -107,7 +107,7 @@ fn build_card(service_socket: std::path::PathBuf) -> Card {
|
||||
Card {
|
||||
schema_version: brahman_card::CARD_SCHEMA_VERSION,
|
||||
id: Ulid::new(),
|
||||
label: "akasha.nous_mock".into(),
|
||||
label: "chasqui.nous_mock".into(),
|
||||
payload: Payload::Virtual,
|
||||
supervision: Supervision::Delegate,
|
||||
lifecycle: Lifecycle::Daemon,
|
||||
@@ -178,7 +178,7 @@ fn handle_embed_file(payload: serde_json::Value, started: Instant) -> Result<Str
|
||||
info!(path = %p.path, "embed_file");
|
||||
|
||||
let file = FileEntry {
|
||||
id: akasha_card::FileId::from(Ulid::new()),
|
||||
id: chasqui_card::FileId::from(Ulid::new()),
|
||||
path: PathBuf::from(p.path),
|
||||
content_hash: None,
|
||||
size: p.size,
|
||||
@@ -204,7 +204,7 @@ fn handle_embed_text(payload: serde_json::Value, started: Instant) -> Result<Str
|
||||
// resto del vector con ceros. No es semánticamente útil, pero respeta
|
||||
// la forma para que el cliente no se rompa.
|
||||
let synthetic = FileEntry {
|
||||
id: akasha_card::FileId::from(Ulid::new()),
|
||||
id: chasqui_card::FileId::from(Ulid::new()),
|
||||
path: PathBuf::from(format!("synthetic://{}", p.text)),
|
||||
content_hash: None,
|
||||
size: p.text.len() as u64,
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "akasha-nous-real"
|
||||
name = "chasqui-nous-real"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
@@ -20,8 +20,8 @@ embeddings = ["dep:fastembed"]
|
||||
[dependencies]
|
||||
brahman-card = { path = "../../../protocol/brahman-card" }
|
||||
brahman-sidecar = { path = "../../../protocol/brahman-sidecar" }
|
||||
ente-cas = { path = "../../../runtime/ente-cas" }
|
||||
akasha-nous = { path = "../nous" }
|
||||
arje-cas = { path = "../../../runtime/arje-cas" }
|
||||
chasqui-nous = { path = "../nous" }
|
||||
serde_json = { workspace = true }
|
||||
sled = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
@@ -36,5 +36,5 @@ fastembed = { version = "4", optional = true }
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[[bin]]
|
||||
name = "akasha-nous-real"
|
||||
name = "chasqui-nous-real"
|
||||
path = "src/main.rs"
|
||||
+4
-4
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! Razón de existir: el modelo real (`fastembed-allMiniLML6V2`) es
|
||||
//! caro (1-50 ms por archivo según tamaño y CPU). Cada vez que el
|
||||
//! daemon de akasha re-publica una Mónada o el watcher dispara un
|
||||
//! daemon de chasqui re-publica una Mónada o el watcher dispara un
|
||||
//! re-cluster por cambio de FS, todos los archivos pasan otra vez
|
||||
//! por embed. Para árboles de 1000 archivos, eso son segundos
|
||||
//! desperdiciados re-embedidando contenido que no cambió.
|
||||
@@ -17,7 +17,7 @@
|
||||
//! little-endian (4 bytes por f32). Compacto, sin overhead de
|
||||
//! bincode/postcard para datos numéricos puros.
|
||||
//! - **Backend**: sled, tree único `embed_cache_v1`. Path:
|
||||
//! `$XDG_CACHE_HOME/brahman/akasha-nous-real-embed-cache.sled`.
|
||||
//! `$XDG_CACHE_HOME/brahman/chasqui-nous-real-embed-cache.sled`.
|
||||
//!
|
||||
//! ## Versionado
|
||||
//!
|
||||
@@ -102,7 +102,7 @@ fn default_path() -> PathBuf {
|
||||
.map(|h| PathBuf::from(h).join(".cache"))
|
||||
})
|
||||
.unwrap_or_else(std::env::temp_dir);
|
||||
base.join("brahman").join("akasha-nous-real-embed-cache.sled")
|
||||
base.join("brahman").join("chasqui-nous-real-embed-cache.sled")
|
||||
}
|
||||
|
||||
fn build_key(file_sha: &[u8; 32], model_id: &str) -> Vec<u8> {
|
||||
@@ -139,7 +139,7 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
fn sha(s: &[u8]) -> [u8; 32] {
|
||||
ente_cas::sha256_of(s)
|
||||
arje_cas::sha256_of(s)
|
||||
}
|
||||
|
||||
#[test]
|
||||
+6
-6
@@ -20,7 +20,7 @@ use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
use fastembed::{EmbeddingModel, InitOptions, TextEmbedding};
|
||||
use akasha_nous::{
|
||||
use chasqui_nous::{
|
||||
EmbedFilePayload, EmbedRequest, EmbedResponse, EmbedTextPayload, ErrorResponse, PingResponse,
|
||||
RequestKind,
|
||||
};
|
||||
@@ -135,13 +135,13 @@ fn handle_file(
|
||||
// bajo la semántica del proveedor (el modelo nunca vio los bytes
|
||||
// adicionales). Si la cabeza cambia, el hash cambia y caemos a
|
||||
// re-embed naturalmente.
|
||||
let file_sha = ente_cas::sha256_of(&buf);
|
||||
let file_sha = arje_cas::sha256_of(&buf);
|
||||
|
||||
if let Some(cache) = cache {
|
||||
if let Some(cached) = cache.get(&file_sha, model_id) {
|
||||
info!(
|
||||
path = %p.path,
|
||||
sha = %ente_cas::hex(&file_sha),
|
||||
sha = %arje_cas::hex(&file_sha),
|
||||
bytes = n,
|
||||
"embed_file: cache HIT"
|
||||
);
|
||||
@@ -156,7 +156,7 @@ fn handle_file(
|
||||
|
||||
info!(
|
||||
path = %p.path,
|
||||
sha = %ente_cas::hex(&file_sha),
|
||||
sha = %arje_cas::hex(&file_sha),
|
||||
bytes = n,
|
||||
"embed_file: cache MISS — invocando modelo"
|
||||
);
|
||||
@@ -166,9 +166,9 @@ fn handle_file(
|
||||
// el cache (sled lo es) pero deja un registro consultable por
|
||||
// herramientas como `ente-cas gc` y permite que otros consumers
|
||||
// resuelvan los bytes por hash.
|
||||
if let Err(e) = ente_cas::store(&buf) {
|
||||
if let Err(e) = arje_cas::store(&buf) {
|
||||
// No-fatal: si CAS no escribe, cacheamos el embedding igual.
|
||||
warn!(error = %e, "ente_cas::store falló (no-fatal)");
|
||||
warn!(error = %e, "arje_cas::store falló (no-fatal)");
|
||||
}
|
||||
|
||||
let text = String::from_utf8_lossy(&buf).to_string();
|
||||
+10
-10
@@ -1,21 +1,21 @@
|
||||
//! `akasha-nous-real` — proveedor Nous con LLM real (gated por feature).
|
||||
//! `chasqui-nous-real` — proveedor Nous con LLM real (gated por feature).
|
||||
//!
|
||||
//! ## Build modes
|
||||
//!
|
||||
//! - `cargo build -p akasha-nous-real`
|
||||
//! - `cargo build -p chasqui-nous-real`
|
||||
//! Compila como **stub**: bin que arranca, sidecarea al brahman-init
|
||||
//! pero rechaza toda request con un error explicando que falta la
|
||||
//! feature. Útil para que `cargo build --workspace` no requiera ML
|
||||
//! deps.
|
||||
//!
|
||||
//! - `cargo build -p akasha-nous-real --features embeddings`
|
||||
//! - `cargo build -p chasqui-nous-real --features embeddings`
|
||||
//! Compila con `fastembed` + ONNX Runtime descargado por Cargo.
|
||||
//! Modelo default: `all-MiniLM-L6-v2` (384-d, ~80 MB descargado al
|
||||
//! primer run y cacheado en `~/.cache/fastembed`).
|
||||
//!
|
||||
//! ## Diseño
|
||||
//!
|
||||
//! Mismo contrato wire que `akasha-nous-mock` (`akasha-nous` crate). La
|
||||
//! Mismo contrato wire que `chasqui-nous-mock` (`chasqui-nous` crate). La
|
||||
//! diferencia operativa: real produce 384-d con semantic content
|
||||
//! (text-embedding del modelo); mock produce 32-d con metadata-hashing.
|
||||
//! No son intercambiables a media-deployment — los centroides de
|
||||
@@ -36,7 +36,7 @@ use brahman_card::{
|
||||
ulid::Ulid, Card, CardKind, ContextBias, Flow, Flows, Lifecycle, Payload, Priority,
|
||||
Supervision, TypeRef,
|
||||
};
|
||||
use akasha_nous::{transport, FLOW_EMBED_REQUEST, FLOW_EMBED_RESULT, FLOW_TYPE_NAME};
|
||||
use chasqui_nous::{transport, FLOW_EMBED_REQUEST, FLOW_EMBED_RESULT, FLOW_TYPE_NAME};
|
||||
use tokio::net::UnixListener;
|
||||
use tracing::info;
|
||||
|
||||
@@ -63,11 +63,11 @@ async fn main() -> std::io::Result<()> {
|
||||
|
||||
#[cfg(not(feature = "embeddings"))]
|
||||
info!(
|
||||
"akasha-nous-real corriendo en modo STUB (compilá con \
|
||||
"chasqui-nous-real corriendo en modo STUB (compilá con \
|
||||
--features embeddings para activar el modelo)"
|
||||
);
|
||||
|
||||
// 1. Resolver socket del data-plane (default `akasha-nous-real.sock`,
|
||||
// 1. Resolver socket del data-plane (default `chasqui-nous-real.sock`,
|
||||
// distinto del mock para coexistir).
|
||||
let sock_path = transport::provider_socket_path("real");
|
||||
if sock_path.exists() {
|
||||
@@ -77,7 +77,7 @@ async fn main() -> std::io::Result<()> {
|
||||
std::fs::create_dir_all(parent)?;
|
||||
}
|
||||
let listener = UnixListener::bind(&sock_path)?;
|
||||
info!(socket = %sock_path.display(), "akasha-nous-real escuchando");
|
||||
info!(socket = %sock_path.display(), "chasqui-nous-real escuchando");
|
||||
|
||||
// 2. Sidecar al brahman-init con Card declarando el socket.
|
||||
let card = build_card(sock_path.clone());
|
||||
@@ -144,7 +144,7 @@ fn init_tracing() {
|
||||
}
|
||||
|
||||
/// Card que real-nous anuncia. Idéntica al mock excepto por:
|
||||
/// - label distinto (`akasha.nous_real`) para que coexistan en el broker.
|
||||
/// - label distinto (`chasqui.nous_real`) para que coexistan en el broker.
|
||||
/// - `priority_contexts.prod = +1` (gana en contexto prod).
|
||||
/// - `service_socket` propio para que clientes lo descubran directo.
|
||||
fn build_card(service_socket: std::path::PathBuf) -> Card {
|
||||
@@ -160,7 +160,7 @@ fn build_card(service_socket: std::path::PathBuf) -> Card {
|
||||
Card {
|
||||
schema_version: brahman_card::CARD_SCHEMA_VERSION,
|
||||
id: Ulid::new(),
|
||||
label: "akasha.nous_real".into(),
|
||||
label: "chasqui.nous_real".into(),
|
||||
payload: Payload::Virtual,
|
||||
supervision: Supervision::Delegate,
|
||||
lifecycle: Lifecycle::Daemon,
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
//! Modo stub: arranca el bin pero rechaza las requests con un error
|
||||
//! que explica que falta la feature `embeddings`.
|
||||
|
||||
use akasha_nous::{EmbedRequest, ErrorResponse};
|
||||
use chasqui_nous::{EmbedRequest, ErrorResponse};
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||
use tokio::net::UnixStream;
|
||||
use tracing::warn;
|
||||
@@ -21,8 +21,8 @@ pub async fn handle_conn(stream: UnixStream) -> std::io::Result<()> {
|
||||
|
||||
let resp = ErrorResponse {
|
||||
error: format!(
|
||||
"akasha-nous-real compilado sin la feature `embeddings`. \
|
||||
Rebuild con: cargo build -p akasha-nous-real --features embeddings"
|
||||
"chasqui-nous-real compilado sin la feature `embeddings`. \
|
||||
Rebuild con: cargo build -p chasqui-nous-real --features embeddings"
|
||||
),
|
||||
};
|
||||
let mut stream = reader.into_inner();
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "akasha-nous"
|
||||
name = "chasqui-nous"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
@@ -1,6 +1,6 @@
|
||||
//! `akasha-nous` — el contrato del proveedor de embeddings.
|
||||
//! `chasqui-nous` — el contrato del proveedor de embeddings.
|
||||
//!
|
||||
//! Define el wire-format compartido entre `akasha-core` (consumidor) y
|
||||
//! Define el wire-format compartido entre `chasqui-core` (consumidor) y
|
||||
//! cualquier implementación de Nous (mock determinista o LLM real). El
|
||||
//! protocolo es **line-delimited JSON** sobre Unix socket: cada conexión
|
||||
//! envía una request, recibe una response, y cierra. Single-shot por
|
||||
@@ -21,8 +21,8 @@
|
||||
//!
|
||||
//! ## Por qué un crate aparte
|
||||
//!
|
||||
//! El consumidor (akasha-core) y el proveedor (akasha-nous-mock,
|
||||
//! akasha-nous-real) deben acordar en types EXACTOS. Tener el contrato
|
||||
//! El consumidor (chasqui-core) y el proveedor (chasqui-nous-mock,
|
||||
//! chasqui-nous-real) deben acordar en types EXACTOS. Tener el contrato
|
||||
//! en su crate evita que cada lado declare structs paralelos que se
|
||||
//! desincronizan. Si bumpeás el wire, bumpeás aquí.
|
||||
//!
|
||||
@@ -32,7 +32,7 @@
|
||||
//! el mismo `flow.output: { name: "embed-result", type: ... }` y
|
||||
//! `flow.input: "embed-request"`. El broker brahman los matchea contra
|
||||
//! los consumidores; el `priority_offset` per-contexto del Card hace que
|
||||
//! mock-nous gane en `test` y real-nous en `prod`. akasha-core sólo
|
||||
//! mock-nous gane en `test` y real-nous en `prod`. chasqui-core sólo
|
||||
//! consume el flow, sin saber cuál implementación corre.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
@@ -118,7 +118,7 @@ pub mod transport {
|
||||
pub const SOCKET_ENV: &str = "NOUSER_NOUS_SOCKET";
|
||||
|
||||
/// Nombre genérico del socket cuando hay un solo proveedor.
|
||||
pub const SOCKET_NAME: &str = "akasha-nous.sock";
|
||||
pub const SOCKET_NAME: &str = "chasqui-nous.sock";
|
||||
|
||||
/// Ruta canónica al socket cuando un único proveedor está activo
|
||||
/// (consumidores que no quieren elegir).
|
||||
@@ -136,7 +136,7 @@ pub mod transport {
|
||||
if let Ok(p) = std::env::var(SOCKET_ENV) {
|
||||
return PathBuf::from(p);
|
||||
}
|
||||
runtime_base().join(format!("akasha-nous-{}.sock", provider))
|
||||
runtime_base().join(format!("chasqui-nous-{}.sock", provider))
|
||||
}
|
||||
|
||||
fn runtime_base() -> PathBuf {
|
||||
@@ -0,0 +1,71 @@
|
||||
# modules/fana/ — Writer DAG editor (absorbe pluma)
|
||||
|
||||
**Propósito.** Editor de escritura multidimensional: el documento es un
|
||||
DAG de átomos narrativos con ramas (timelines), tracking de coherencia,
|
||||
e indexación semántica. Absorbe el linaje markdown de `pluma`. Prioridad
|
||||
alta entre las apps.
|
||||
|
||||
## Estado
|
||||
|
||||
- **Existente (de pluma)**: `fana-md` (parser markdown, ex `pluma-md`),
|
||||
`fana-md-reader-web` (lector DOM, ex `pluma-reader-web`, aún dep de
|
||||
`gioser-web`).
|
||||
- **Planeado**: el resto de sub-crates (writer DAG editor completo).
|
||||
|
||||
## Crates (objetivo)
|
||||
|
||||
| crate | tipo | rol |
|
||||
| ---------------------- | ---- | ---------------------------------------------------- |
|
||||
| `fana-core` | lib | `NarrativeAtom` + `NarrativeGraph` + `CoherenceState`|
|
||||
| `fana-md` | lib | Parser markdown (ex pluma-md) |
|
||||
| `fana-graph` | lib | DAG ops + `propagate_mutation` topológico |
|
||||
| `fana-semantic` | lib | Cliente `verbo` + scoring de intensidad adjetiva |
|
||||
| `fana-store` | lib | Persistencia sled/RocksDB + bincode/rkyv zero-copy |
|
||||
| `fana-llm` | lib | Cliente HTTP a LLMs remotos (evaluación + merge) |
|
||||
| `fana-render-plan` | lib | DrawCommands agnósticos (editor + sidepane + ghost) |
|
||||
| `fana-editor-gpui` | lib | WorkspaceEditor View + OscilloscopeSidepane + Ghost |
|
||||
| `fana-md-reader-web` | lib | Lector markdown DOM (ex pluma-reader-web) |
|
||||
| `fana-editor-web` | lib | (futuro) editor WASM |
|
||||
|
||||
## Modelo de datos
|
||||
|
||||
```rust
|
||||
enum CoherenceState { Valid, InConflict { origin, reason }, PendingEvaluation }
|
||||
|
||||
struct NarrativeAtom {
|
||||
id: Uuid,
|
||||
content_hash: [u8; 32], // SHA-256 estricto
|
||||
content: Arc<String>, // texto compartido (zero-alloc al ramificar)
|
||||
semantic_vectors: HashMap<String, f32>, // concepto → intensidad
|
||||
dependencies: Vec<Uuid>, // nodos prerrequisito
|
||||
branch_id: String,
|
||||
coherence: CoherenceState,
|
||||
}
|
||||
|
||||
struct NarrativeGraph {
|
||||
nodes: HashMap<Uuid, NarrativeAtom>,
|
||||
adjacency_list: HashMap<Uuid, Vec<Uuid>>, // padre → hijos dependientes
|
||||
}
|
||||
```
|
||||
|
||||
## Dependencias
|
||||
|
||||
- `fana-semantic` ← `verbo` (embeddings, instancia modelo ligero ~384d).
|
||||
- `fana-md` puro (sin deps de host).
|
||||
- `fana-md-reader-web` + `fana-editor-web` ← `wasm-bindgen`, `web-sys`.
|
||||
- `fana-editor-gpui` ← `gpui`, `nahual`.
|
||||
- `gioser-web` sigue consumiendo `fana-md-reader-web`.
|
||||
|
||||
## Invariantes
|
||||
|
||||
- Toda mutación de texto valida contra el hash binario del contenido.
|
||||
- Branches comparten texto vía `Arc<String>` — clonar una rama es O(1).
|
||||
- `propagate_mutation` marca `PendingEvaluation` en cascada topológica
|
||||
cuando un átomo origen cambia (shock-wave lógica).
|
||||
- Separabilidad UI estricta: `fana-core/md/graph/semantic/store/llm/
|
||||
render-plan` agnósticos; `fana-editor-{gpui,web}` intercambiables.
|
||||
|
||||
## Apps
|
||||
|
||||
- `apps/fana` — binario GPUI (prioridad alta).
|
||||
- `apps/fana-web` — (futuro) cdylib WASM.
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "pluma-reader-web"
|
||||
name = "fana-md-reader-web"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
@@ -7,7 +7,7 @@ authors.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
pluma-md = { path = "../pluma-md" }
|
||||
fana-md = { path = "../fana-md" }
|
||||
wasm-bindgen.workspace = true
|
||||
wasm-bindgen-futures.workspace = true
|
||||
js-sys.workspace = true
|
||||
+1
-1
@@ -53,7 +53,7 @@ impl Reader {
|
||||
|
||||
/// Renderea un string markdown directamente, sin fetch.
|
||||
pub fn render_md(&self, md: &str, theme: &str) {
|
||||
let html = pluma_md::to_themed_html(md, theme);
|
||||
let html = fana_md::to_themed_html(md, theme);
|
||||
self.container.set_inner_html(&html);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "pluma-md"
|
||||
name = "fana-md"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
@@ -8,7 +8,7 @@
|
||||
//! border-bottom = `theme.border`.
|
||||
//! - Padding 16/12, text_size 14.
|
||||
//!
|
||||
//! Patrón emergente: `nakui-explorer`, `akasha-explorer`,
|
||||
//! Patrón emergente: `nakui-explorer`, `chasqui-explorer`,
|
||||
//! `minga-explorer`, `brahman-broker-explorer` declaran headers
|
||||
//! idénticos sólo cambiando el label. Ahora es 1 línea.
|
||||
//!
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# modules/pluma/ — Markdown agnóstico + visor web
|
||||
|
||||
**Propósito.** Parser de markdown que no asume host: produce un árbol
|
||||
de `Block`. El visor web fetch-ea un `.md` y lo inyecta como HTML,
|
||||
respetando `data-pluma-theme` del contenedor.
|
||||
|
||||
## Crates
|
||||
|
||||
| crate | tipo | rol |
|
||||
| -------------------- | ---- | ------------------------------------------------ |
|
||||
| `pluma-md` | lib | Wrapper sobre `pulldown-cmark` con AST simple |
|
||||
| `pluma-reader-web` | lib | Reader DOM: fetch + inject HTML + theming |
|
||||
|
||||
## Dependencias
|
||||
|
||||
- `pluma-md` ← `pulldown-cmark` (sin features de host).
|
||||
- `pluma-reader-web` ← `wasm-bindgen` + `web-sys` (HtmlElement, Response).
|
||||
- Consumido por: `apps/gioser-web` (renderea los 4 tips elementales
|
||||
desde `md/agua.md`, `md/aire.md`, `md/fuego.md`, `md/tierra.md`).
|
||||
|
||||
## Estado
|
||||
|
||||
LOC 178. Funcional y pequeño. Sin tests (todavía). Pendiente: AST
|
||||
con todos los inline elements (links, emphasis) accesibles desde Rust.
|
||||
@@ -1,4 +1,4 @@
|
||||
# modules/vista/ — Deck horizontal swipe (PageView)
|
||||
# modules/revista/ — Deck horizontal swipe (PageView)
|
||||
|
||||
**Propósito.** Carousel/PageView estilo Flutter: gesto horizontal con
|
||||
snap a página, distinción horizontal vs vertical, soporte mouse +
|
||||
@@ -8,15 +8,15 @@ touch + pointer events. Lógica separada del binding DOM.
|
||||
|
||||
| crate | tipo | rol |
|
||||
| ------------- | ---- | --------------------------------------------------------- |
|
||||
| `vista-core` | lib | `DeckState` agnóstico: pointer_down/move/end → outcomes |
|
||||
| `vista-web` | lib | Binding DOM sobre `<strip>`: traduce eventos + aplica CSS |
|
||||
| `revista-core` | lib | `DeckState` agnóstico: pointer_down/move/end → outcomes |
|
||||
| `revista-web` | lib | Binding DOM sobre `<strip>`: traduce eventos + aplica CSS |
|
||||
|
||||
## Dependencias
|
||||
|
||||
- `vista-core`: sin deps externas. Pura state machine.
|
||||
- `vista-web` ← `vista-core`, `wasm-bindgen`, `web-sys` (PointerEvent).
|
||||
- `revista-core`: sin deps externas. Pura state machine.
|
||||
- `revista-web` ← `revista-core`, `wasm-bindgen`, `web-sys` (PointerEvent).
|
||||
|
||||
## API agnóstica (vista-core)
|
||||
## API agnóstica (revista-core)
|
||||
|
||||
```rust
|
||||
let mut deck = DeckState::new();
|
||||
@@ -35,6 +35,6 @@ if let Some(r) = deck.pointer_end(offset, width, n_pages) {
|
||||
|
||||
## Estado
|
||||
|
||||
vista-core: 5 tests verdes (drag decision + snap + clamp + goto).
|
||||
vista-web: binding DOM intacto, ahora delega toda la lógica a core.
|
||||
revista-core: 5 tests verdes (drag decision + snap + clamp + goto).
|
||||
revista-web: binding DOM intacto, ahora delega toda la lógica a core.
|
||||
LOC core 177 + web ~355. Reutilizable en backends no-web.
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "vista-core"
|
||||
name = "revista-core"
|
||||
description = "Vista — máquina de estados agnóstica para deck horizontal con snap. Sin dependencias web/DOM."
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "vista-web"
|
||||
name = "revista-web"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
@@ -7,7 +7,7 @@ authors.workspace = true
|
||||
publish.workspace = true
|
||||
|
||||
[dependencies]
|
||||
vista-core = { path = "../vista-core" }
|
||||
revista-core = { path = "../revista-core" }
|
||||
wasm-bindgen.workspace = true
|
||||
js-sys.workspace = true
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
use vista_core::{DeckState, DragOutcome};
|
||||
use revista_core::{DeckState, DragOutcome};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{Event, HtmlElement, PointerEvent};
|
||||
@@ -6,13 +6,13 @@ rust-version.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
publish.workspace = true
|
||||
description = "Runtime de shipote: WorkspaceManager sobre ente-incarnate. Estado in-memory, lifecycle, reaping."
|
||||
description = "Runtime de shuma: WorkspaceManager sobre arje-incarnate. Estado in-memory, lifecycle, reaping."
|
||||
|
||||
[dependencies]
|
||||
shuma-card = { path = "../shuma-card" }
|
||||
shuma-discern = { path = "../shuma-discern" }
|
||||
brahman-card = { path = "../../../protocol/brahman-card" }
|
||||
ente-incarnate = { path = "../../../init/ente-incarnate" }
|
||||
arje-incarnate = { path = "../../../init/arje-incarnate" }
|
||||
nix = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -18,7 +18,7 @@ pub mod pipeline;
|
||||
pub mod stats;
|
||||
|
||||
use brahman_card::{Card, Payload, Supervision};
|
||||
use ente_incarnate::{Incarnator, IncarnatorConfig};
|
||||
use arje_incarnate::{Incarnator, IncarnatorConfig};
|
||||
use nix::sys::signal::{kill, Signal};
|
||||
use nix::sys::wait::{waitpid, WaitPidFlag, WaitStatus};
|
||||
use nix::unistd::Pid;
|
||||
@@ -38,7 +38,7 @@ pub enum CoreError {
|
||||
#[error("compile: {0}")]
|
||||
Compile(#[from] shuma_card::CompileError),
|
||||
#[error("incarnate: {0}")]
|
||||
Incarnate(#[from] ente_incarnate::IncarnateError),
|
||||
Incarnate(#[from] arje_incarnate::IncarnateError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -682,9 +682,9 @@ impl WorkspaceManager {
|
||||
// hace OOM kill al exceder memory.max — enforcement automático
|
||||
// sin policy adicional. Falla silenciosa si no hay delegation.
|
||||
if !spec.soma.cgroup.path.is_empty() {
|
||||
if let Ok(abs) = ente_incarnate::cgroup::ensure_cgroup(&spec.soma.cgroup) {
|
||||
if let Ok(abs) = arje_incarnate::cgroup::ensure_cgroup(&spec.soma.cgroup) {
|
||||
let applied =
|
||||
ente_incarnate::cgroup::apply_rlimits_to_cgroup(&abs, &spec.soma.rlimits);
|
||||
arje_incarnate::cgroup::apply_rlimits_to_cgroup(&abs, &spec.soma.rlimits);
|
||||
if !applied.is_empty() {
|
||||
warnings.push(format!("cgroup limits applied: {}", applied.join(", ")));
|
||||
}
|
||||
@@ -842,11 +842,11 @@ impl WorkspaceManager {
|
||||
use std::os::fd::IntoRawFd;
|
||||
let (sout_r, sout_w) =
|
||||
nix::unistd::pipe2(nix::fcntl::OFlag::O_CLOEXEC).map_err(|e| {
|
||||
CoreError::Incarnate(ente_incarnate::IncarnateError::Pipe(e))
|
||||
CoreError::Incarnate(arje_incarnate::IncarnateError::Pipe(e))
|
||||
})?;
|
||||
let (serr_r, serr_w) =
|
||||
nix::unistd::pipe2(nix::fcntl::OFlag::O_CLOEXEC).map_err(|e| {
|
||||
CoreError::Incarnate(ente_incarnate::IncarnateError::Pipe(e))
|
||||
CoreError::Incarnate(arje_incarnate::IncarnateError::Pipe(e))
|
||||
})?;
|
||||
let sout_r_fd = sout_r.into_raw_fd();
|
||||
let sout_w_fd = sout_w.into_raw_fd();
|
||||
@@ -856,7 +856,7 @@ impl WorkspaceManager {
|
||||
let stdout_buf = logbuf::LogBuf::new();
|
||||
let stderr_buf = logbuf::LogBuf::new();
|
||||
|
||||
let stdio = ente_incarnate::ChildStdio {
|
||||
let stdio = arje_incarnate::ChildStdio {
|
||||
stdin_fd: None,
|
||||
stdout_fd: Some(sout_w_fd),
|
||||
stderr_fd: Some(serr_w_fd),
|
||||
|
||||
@@ -282,7 +282,7 @@ pub struct RestoreOutcome {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::WorkspaceManager;
|
||||
use ente_incarnate::IncarnatorConfig;
|
||||
use arje_incarnate::IncarnatorConfig;
|
||||
use shuma_card::{ExitPolicy, WorkspaceSpec};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Pipeline runtime: encadena nodos con pipes y opcionalmente intercepta
|
||||
//! cada flow para discernir su contenido.
|
||||
//!
|
||||
//! Cada nodo se encarna via [`ente_incarnate::Incarnator`] — eso significa
|
||||
//! Cada nodo se encarna via [`arje_incarnate::Incarnator`] — eso significa
|
||||
//! que **cada comando puede tener su propio SomaSpec** (namespaces, cgroup,
|
||||
//! rlimits) heredado del workspace. La conexión stdin↔stdout se hace con
|
||||
//! `pipe2(2)` + `ChildStdio` declarativo: el callback de clone(2) hace los
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
use crate::CoreError;
|
||||
use brahman_card::Payload;
|
||||
use ente_incarnate::{ChildStdio, Incarnator};
|
||||
use arje_incarnate::{ChildStdio, Incarnator};
|
||||
use nix::fcntl::OFlag;
|
||||
use nix::unistd::pipe2;
|
||||
use shuma_card::PipelineSpec;
|
||||
@@ -87,7 +87,7 @@ pub async fn run_pipeline(
|
||||
let mut edge_w: Vec<RawFd> = vec![-1; spec.edges.len()];
|
||||
for i in 0..spec.edges.len() {
|
||||
let (r, w) = pipe2(OFlag::O_CLOEXEC).map_err(|e| {
|
||||
CoreError::Incarnate(ente_incarnate::IncarnateError::Pipe(e))
|
||||
CoreError::Incarnate(arje_incarnate::IncarnateError::Pipe(e))
|
||||
})?;
|
||||
edge_r[i] = r.into_raw_fd();
|
||||
edge_w[i] = w.into_raw_fd();
|
||||
@@ -110,7 +110,7 @@ pub async fn run_pipeline(
|
||||
}
|
||||
// Splitter: pipe propio para el productor → splitter lee y replica a edge_w[*].
|
||||
let (prod_r, prod_w) = pipe2(OFlag::O_CLOEXEC).map_err(|e| {
|
||||
CoreError::Incarnate(ente_incarnate::IncarnateError::Pipe(e))
|
||||
CoreError::Incarnate(arje_incarnate::IncarnateError::Pipe(e))
|
||||
})?;
|
||||
producer_stdout_fd[i] = Some(prod_w.into_raw_fd());
|
||||
let prod_r_fd = prod_r.into_raw_fd();
|
||||
@@ -147,7 +147,7 @@ pub async fn run_pipeline(
|
||||
// Merger: lee de N edge_r y escribe a un nuevo pipe cuyo
|
||||
// read end es el stdin del consumer.
|
||||
let (cons_r, cons_w) = pipe2(OFlag::O_CLOEXEC).map_err(|e| {
|
||||
CoreError::Incarnate(ente_incarnate::IncarnateError::Pipe(e))
|
||||
CoreError::Incarnate(arje_incarnate::IncarnateError::Pipe(e))
|
||||
})?;
|
||||
consumer_stdin_fd[j] = Some(cons_r.into_raw_fd());
|
||||
let inputs: Vec<RawFd> = predecessors[j]
|
||||
@@ -169,7 +169,7 @@ pub async fn run_pipeline(
|
||||
Payload::Native { .. } | Payload::Legacy { .. } => {}
|
||||
_ => {
|
||||
return Err(CoreError::Incarnate(
|
||||
ente_incarnate::IncarnateError::NonExecutablePayload,
|
||||
arje_incarnate::IncarnateError::NonExecutablePayload,
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -638,7 +638,7 @@ fn _keep_raw(_: &dyn AsRawFd) {}
|
||||
mod tests {
|
||||
use super::*;
|
||||
use brahman_card::Payload;
|
||||
use ente_incarnate::IncarnatorConfig;
|
||||
use arje_incarnate::IncarnatorConfig;
|
||||
use shuma_card::{CommandRef, DiscernPolicy, FlowEdge, PipelineSpec, WorkspaceId};
|
||||
|
||||
fn cmd(label: &str, exec: &str, argv: &[&str]) -> CommandRef {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! Trait + pipeline + discerners default. Devuelve un [`Discernment`] con
|
||||
//! `TypeRef` consistente con el broker, confidence, MIME y un `lens` hint
|
||||
//! para UIs (reusa el espíritu del `dominant_lens` de akasha).
|
||||
//! para UIs (reusa el espíritu del `dominant_lens` de chasqui).
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user