feat(yahweh-meta-runtime): promover short_hash y preview_value desde nakui-explorer
Continúa la integración de apps nakui al stack yahweh. Los helpers visuales que nakui-explorer tenía locales y son reusables suben a yahweh-meta-runtime/format. yahweh-meta-runtime: - short_hash(h: &[u8; 32]) -> String: hex de los primeros 4 bytes. - preview_value(v: &Value, max: usize) -> String: JSON one-liner truncado con "..." (edge case max < 3 sin panic). - 5 tests nuevos. nakui-explorer: - Nueva dep yahweh-meta-runtime. - Borrado helpers locales (short_uuid + short_hash + preview_value) + 4 tests duplicados. - Imports desde yahweh-meta-runtime. Tests: 42→47 yahweh-meta-runtime, 7→3 nakui-explorer (los 3 que quedan son específicos del explorer: load_log, breakdown, missing_file). Resto intacto. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,46 @@ ratio/diff ver `git show <sha>`.
|
||||
|
||||
## 2026-05-10
|
||||
|
||||
### feat(yahweh-meta-runtime): promover `short_hash` y `preview_value` desde nakui-explorer
|
||||
Continúa la integración de las apps nakui al stack yahweh. Los
|
||||
helpers visuales que `nakui-explorer` tenía locales y son reusables
|
||||
suben a `yahweh-meta-runtime/format` para que cualquier app pueda
|
||||
consumirlos sin duplicar.
|
||||
|
||||
Cambios en `yahweh-meta-runtime`:
|
||||
- **`pub fn short_hash(h: &[u8; 32]) -> String`**: hex de los
|
||||
primeros 4 bytes (8 chars). Útil para mostrar bundle/schema
|
||||
hashes en UI sin quemar pantalla.
|
||||
- **`pub fn preview_value(v: &Value, max: usize) -> String`**:
|
||||
JSON one-liner truncado con `...` al final si excede `max`
|
||||
chars. Edge case: `max < 3` devuelve los primeros `max` chars
|
||||
sin sufijo.
|
||||
- Re-exports en lib.
|
||||
- 5 tests nuevos: 4 tests + 1 sanity para el caso `max < ellipsis`.
|
||||
|
||||
Migración de `nakui-explorer`:
|
||||
- Nueva dep `yahweh-meta-runtime` en Cargo.toml.
|
||||
- Borrado helpers locales `short_uuid`, `short_hash`,
|
||||
`preview_value` (~30 líneas).
|
||||
- `use yahweh_meta_runtime::{preview_value, short_hash, short_uuid}`.
|
||||
- Borrados 4 tests duplicados (los runtime los testea).
|
||||
|
||||
Tests:
|
||||
- `yahweh-meta-runtime`: 42 → **47** (+5 helpers nuevos).
|
||||
- `nakui-explorer`: 7 → **3** (–4 duplicados; quedan los 3
|
||||
específicos: load_log, breakdown, missing_file).
|
||||
- Resto del workspace intacto.
|
||||
|
||||
Beneficio operativo: 3 helpers visuales centralizados. Cualquier
|
||||
app nueva que muestre UUIDs/hashes/JSON-previews los importa sin
|
||||
re-implementar la heurística de truncamiento.
|
||||
|
||||
Pendiente arquitectural: el render del card timeline en
|
||||
`nakui-explorer` (border-l-4 colored + flex_col + texto en niveles)
|
||||
es un pattern reusable que también aparece en `yahweh-widget-meta-form`
|
||||
(render_list filas). Cuando aparezca un tercer consumer de ese
|
||||
pattern se extrae a un widget yahweh.
|
||||
|
||||
### feat(brahman-cards): templates Nickel canónicos para cada body kind
|
||||
Materializa el patrón "import + override" del brazo: hasta ahora
|
||||
`BRAHMAN_CARDS_TEMPLATES_DIR` existía como mecanismo pero el repo
|
||||
|
||||
@@ -7,6 +7,7 @@ description = "Explorador GPUI del event log de Nakui: timeline de seeds + morph
|
||||
|
||||
[dependencies]
|
||||
nakui-core = { path = "../../modules/nakui/core" }
|
||||
yahweh-meta-runtime = { path = "../../modules/ui_engine/libs/meta-runtime" }
|
||||
gpui = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
uuid = { workspace = true, features = ["serde"] }
|
||||
|
||||
@@ -30,6 +30,7 @@ use gpui::{
|
||||
SharedString, Window, WindowBounds, WindowOptions,
|
||||
};
|
||||
use nakui_core::event_log::{EventLog, LogEntry};
|
||||
use yahweh_meta_runtime::{preview_value, short_hash, short_uuid};
|
||||
|
||||
const REFRESH_INTERVAL: Duration = Duration::from_secs(2);
|
||||
|
||||
@@ -378,35 +379,8 @@ impl Render for Explorer {
|
||||
}
|
||||
}
|
||||
|
||||
fn short_uuid(id: &uuid::Uuid) -> String {
|
||||
let s = id.to_string();
|
||||
if s.len() > 8 {
|
||||
s[..8].to_string()
|
||||
} else {
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
fn short_hash(h: &[u8; 32]) -> String {
|
||||
let mut s = String::with_capacity(8);
|
||||
for b in h.iter().take(4) {
|
||||
use std::fmt::Write;
|
||||
let _ = write!(s, "{:02x}", b);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Renderiza un `serde_json::Value` en una sola línea limitada a `max`
|
||||
/// caracteres (para preview en la timeline, no para edición).
|
||||
fn preview_value(v: &serde_json::Value, max: usize) -> String {
|
||||
let s = v.to_string();
|
||||
if s.chars().count() <= max {
|
||||
s
|
||||
} else {
|
||||
let truncated: String = s.chars().take(max - 3).collect();
|
||||
format!("{truncated}...")
|
||||
}
|
||||
}
|
||||
// Helpers `short_uuid`, `short_hash`, `preview_value` viven en
|
||||
// `yahweh_meta_runtime::format`. Se usan acá via el `use` de arriba.
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -472,34 +446,8 @@ mod tests {
|
||||
assert!(result.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preview_value_truncates_long_strings() {
|
||||
let v = serde_json::json!({"a": "x".repeat(200)});
|
||||
let p = preview_value(&v, 30);
|
||||
assert!(p.len() <= 30);
|
||||
assert!(p.ends_with("..."));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preview_value_keeps_short_strings_intact() {
|
||||
let v = serde_json::json!({"a": 1});
|
||||
let p = preview_value(&v, 30);
|
||||
assert_eq!(p, "{\"a\":1}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_uuid_takes_first_8_chars() {
|
||||
let id = uuid::Uuid::parse_str("a1b2c3d4-e5f6-7890-abcd-ef1234567890").unwrap();
|
||||
assert_eq!(short_uuid(&id), "a1b2c3d4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_hash_takes_first_4_bytes_hex() {
|
||||
let mut h = [0u8; 32];
|
||||
h[0] = 0xaa;
|
||||
h[1] = 0xbb;
|
||||
h[2] = 0xcc;
|
||||
h[3] = 0xdd;
|
||||
assert_eq!(short_hash(&h), "aabbccdd");
|
||||
}
|
||||
// Tests de `short_uuid` / `short_hash` / `preview_value` viven
|
||||
// en `yahweh-meta-runtime::format` tras la migración. Si esos se
|
||||
// vuelven a romper, los tests específicos del crate runtime los
|
||||
// capturan; acá no duplicamos.
|
||||
}
|
||||
|
||||
@@ -52,6 +52,36 @@ pub fn short_uuid(id: &Uuid) -> String {
|
||||
id.to_string().chars().take(8).collect()
|
||||
}
|
||||
|
||||
/// Hex string de los primeros 4 bytes de un hash SHA-256 (8
|
||||
/// caracteres). Útil para mostrar bundle/schema hashes en UI sin
|
||||
/// quemar pantalla con los 64 chars completos.
|
||||
pub fn short_hash(h: &[u8; 32]) -> String {
|
||||
use std::fmt::Write;
|
||||
let mut s = String::with_capacity(8);
|
||||
for b in h.iter().take(4) {
|
||||
let _ = write!(s, "{:02x}", b);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Renderea un `serde_json::Value` en una sola línea, truncado a
|
||||
/// `max` caracteres con `...` al final si excede. Para preview en
|
||||
/// timelines/cards/listas — NO para edición.
|
||||
///
|
||||
/// `max` es un upper-bound aproximado: el resultado nunca excede
|
||||
/// `max` chars, pero puede ser más corto si el value es chico.
|
||||
pub fn preview_value(v: &Value, max: usize) -> String {
|
||||
let s = v.to_string();
|
||||
if s.chars().count() <= max {
|
||||
s
|
||||
} else if max < 3 {
|
||||
s.chars().take(max).collect()
|
||||
} else {
|
||||
let truncated: String = s.chars().take(max - 3).collect();
|
||||
format!("{truncated}...")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -105,6 +135,45 @@ mod tests {
|
||||
assert_eq!(value_to_input_text(&json!(42)), "42");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_hash_takes_first_4_bytes_hex() {
|
||||
let mut h = [0u8; 32];
|
||||
h[0] = 0xaa;
|
||||
h[1] = 0xbb;
|
||||
h[2] = 0xcc;
|
||||
h[3] = 0xdd;
|
||||
assert_eq!(short_hash(&h), "aabbccdd");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_hash_zeros() {
|
||||
let h = [0u8; 32];
|
||||
assert_eq!(short_hash(&h), "00000000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preview_value_keeps_short_strings_intact() {
|
||||
let v = json!({"a": 1});
|
||||
assert_eq!(preview_value(&v, 30), "{\"a\":1}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preview_value_truncates_long_strings_with_ellipsis() {
|
||||
let v = json!({"a": "x".repeat(200)});
|
||||
let p = preview_value(&v, 30);
|
||||
assert!(p.chars().count() <= 30);
|
||||
assert!(p.ends_with("..."));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preview_value_handles_max_smaller_than_ellipsis() {
|
||||
// Edge case: max < 3 (no espacio para "..."). Devuelve
|
||||
// los primeros `max` chars sin sufijo, sin panic.
|
||||
let v = json!("xxxxxxxxxxxxxxxx");
|
||||
let p = preview_value(&v, 2);
|
||||
assert!(p.chars().count() <= 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn short_uuid_returns_first_8_chars() {
|
||||
let id = Uuid::parse_str("01ARZ3ND-EKTS-V4RR-FFQ6-9G5FAV000000").ok();
|
||||
|
||||
@@ -30,6 +30,9 @@ pub mod refs;
|
||||
|
||||
pub use backend::{MetaBackend, WriteOutcome};
|
||||
pub use delta::{compute_clear_fields, compute_field_delta};
|
||||
pub use format::{human_label_for_record, render_value, short_uuid, value_to_input_text};
|
||||
pub use format::{
|
||||
human_label_for_record, preview_value, render_value, short_hash, short_uuid,
|
||||
value_to_input_text,
|
||||
};
|
||||
pub use parse::{infer_param_value, parse_field_value, resolve_param_value};
|
||||
pub use refs::validate_entity_refs;
|
||||
|
||||
Reference in New Issue
Block a user