feat(tahuantinsuyu): scaffolding del estudio astrológico (10 crates + ventana 3-panes)

Módulo nuevo `modules/tahuantinsuyu/` con 9 crates reusables + app
`apps/tahuantinsuyu` ejecutable que abre la ventana del explorador y
coordina los widgets:

- tahuantinsuyu-card: Card Brahman + spawn_sidecar (flows
  chart-request/chart-result).
- tahuantinsuyu-model: tipos agnósticos (Group/Contact/Chart,
  StoredBirthData, StoredChartConfig, ChartKind, TreeSelection).
- tahuantinsuyu-store: persistencia SQLite (rusqlite) con migración v1,
  CRUD por entidad y descenso recursivo `charts_under_group`.
- tahuantinsuyu-engine: bridge agnóstico al canvas vía `RenderModel`
  (Layer/Glyph/Geometry). Feature `eternal-bridge` (off por default)
  reservada para enchufar eternal-astrology desde ~/eternal.
- tahuantinsuyu-modules: registry de módulos pluggables (Module trait
  + Control schema) con `NatalModule` placeholder.
- tahuantinsuyu-theme: AstroPalette (elementos / modos / planetas /
  aspectos) con variantes dark + light sobre yahweh-theme.
- tahuantinsuyu-canvas: widget GPUI con CanvasState (Empty / Wheel /
  Thumbnails). Render placeholder hasta cablear la rueda real.
- tahuantinsuyu-tree: explorador izquierdo sobre yahweh-widget-tree,
  prefijos g:/c:/h: para Group/Contact/Chart.
- tahuantinsuyu-panel: control panel inferior que lee Controls de los
  módulos del registry y los pinta.
- apps/tahuantinsuyu: binario `tahuantinsuyu` (launch_app-style) con
  Shell coordinador (tree↔canvas↔panel), DB en $XDG_DATA_HOME.

Workspace Cargo.toml actualizado con los 10 miembros. `cargo check`
verde, tests unitarios verdes (model/store/engine/modules/theme/card).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-16 01:06:03 +00:00
parent e8f97b50cb
commit c48638fe87
23 changed files with 3256 additions and 0 deletions
@@ -0,0 +1,11 @@
[package]
name = "tahuantinsuyu-card"
version = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
description = "Tahuantinsuyu — Tarjeta de Presentación brahman + spawn del sidecar."
[dependencies]
brahman-card = { path = "../../../core/brahman-card" }
brahman-sidecar = { path = "../../../shared/brahman-sidecar" }
ulid = { workspace = true }
@@ -0,0 +1,89 @@
//! `tahuantinsuyu-card` — Tarjeta de Presentación + sidecar de la app.
//!
//! Cualquier binario que levante Tahuantinsuyu llama [`spawn_sidecar`]
//! antes de abrir la ventana GPUI. La lógica de thread / tokio /
//! ping-loop vive en `brahman-sidecar`; aquí solo declaramos quién es
//! Tahuantinsuyu como módulo Brahman.
#![forbid(unsafe_code)]
#![warn(rust_2018_idioms)]
use std::collections::BTreeSet;
use brahman_card::{
Card, Flow, Flows, FsPolicy, IpcPolicy, Lifecycle, Payload, Permissions, Priority, Supervision,
TypeRef, CARD_SCHEMA_VERSION,
};
use ulid::Ulid;
/// Label canónico — coincide con el binario y aparece en `ListEntes`.
pub const LABEL: &str = "brahman.tahuantinsuyu";
/// Spawn fire-and-forget. Si el Init no está corriendo, el sidecar
/// loggea y termina; la app sigue ejecutándose standalone.
pub fn spawn_sidecar() {
brahman_sidecar::spawn(build_card());
}
/// Construye la Card. Expuesto público para tests + para shells que
/// quieran inspeccionar el manifiesto antes de spawnear.
pub fn build_card() -> Card {
Card {
schema_version: CARD_SCHEMA_VERSION,
id: Ulid::new(),
lineage: None,
label: LABEL.into(),
provides: BTreeSet::new(),
requires: BTreeSet::new(),
payload: Payload::Virtual,
supervision: Supervision::Delegate,
lifecycle: Lifecycle::Widget,
priority: Priority::Normal,
permissions: Permissions {
// La app guarda su DB SQLite en disco; necesita RW filesystem.
filesystem: FsPolicy::ReadWrite,
ipc: IpcPolicy {
allow: vec!["wit-v1".into()],
},
..Default::default()
},
flow: Flows {
// Recibe peticiones de cómputo (carta natal, transit, etc.)
// serializadas como JSON. La forma exacta la define
// `tahuantinsuyu-engine`.
input: vec![Flow {
name: "chart-request".into(),
ty: TypeRef::Primitive {
name: "json".into(),
},
pin_to: None,
}],
// Publica el resultado de un cómputo (placements, aspectos,
// casas) también como JSON. Otras apps brahman pueden
// consumirlo para visualizar o derivar.
output: vec![Flow {
name: "chart-result".into(),
ty: TypeRef::Primitive {
name: "json".into(),
},
pin_to: None,
}],
},
..Default::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn card_label_and_flow() {
let c = build_card();
assert_eq!(c.label, LABEL);
assert_eq!(c.flow.input.len(), 1);
assert_eq!(c.flow.output.len(), 1);
assert_eq!(c.flow.input[0].name, "chart-request");
assert_eq!(c.flow.output[0].name, "chart-result");
}
}