Skip to main content
Glama
uranotools

urano-charts

Official
by uranotools
README.md
<div align="center">

# Urano Charts — Gráficas avanzadas OSS

[![Urano Core Compatibility](https://img.shields.io/badge/Urano_Core-%E2%89%A5_1.5.0-blueviolet?style=for-the-badge&logo=electron)](https://github.com/uranotools/UranoDesktop)
[![Type](https://img.shields.io/badge/Plugin_Type-MCP_%2B_JsonLive_Widgets-cyan?style=for-the-badge&logo=typescript)](https://github.com/uranotools/UranoDesktop)
[![Platform](https://img.shields.io/badge/Platform-Desktop_%2B_Cloud-orange?style=for-the-badge&logo=windows)](https://github.com/uranotools/UranoDesktop)
[![Licence](https://img.shields.io/badge/Licence-MIT-green?style=for-the-badge)](./LICENSE)

**Widgets JsonLive propios (uPlot + ECharts) para series temporales con zoom/pan, box plots y coordenadas paralelas — gratis, open-source, sin API keys ni CDN.**

*Complementa el `Chart` nativo del host; no lo reemplaza.*

</div>

---

## 1. Descripción humana

### Para quién es

Quien necesita gráficas que el widget nativo `Chart` no cubre bien (zoom fluido, cuartiles, exploración multivariada) y quiere instalarlas como MCP plug-and-play en UranoDesktop / Cloud.

### Qué problema resuelve

- El host ya pinta bar/line/pie/heatmap/sankey/etc. con `Chart`.
- Faltan tipos “avanzados” sin tocar `UranoFront` ni `COMPONENT_MAP`.
- No quieres depender de SaaS, keys ni scripts remotos: todo va en el ZIP del pack.

### Casos de uso

| Situación | Qué hace el agente |
|-----------|-------------------|
| Serie temporal larga con zoom | `build_timeseries_uispec` → `charts.TimeSeries` (uPlot) |
| Comparar distribuciones | `build_boxplot_uispec` → `charts.BoxPlot` |
| Perfiles multivariados | `build_parallel_uispec` → `charts.Parallel` |
| Smoke test post-install | `demo_uispec` → `urano_render_json` |
| Bar / line / pie / heatmap… | Widget **nativo** `Chart` (no este pack) |

### Capacidades

| Área | Capacidad |
|------|-----------|
| TimeSeries | uPlot — zoom/pan, multi-serie |
| BoxPlot | ECharts — cuartiles + outliers (muestras raw) |
| Parallel | ECharts — coordenadas paralelas |
| Tools | Builders de uiSpec + catálogo + demo |
| Coste | MIT + deps OSS; **cero** Vault / API keys / fetch remoto |
| UI | Types namespaced `charts.*` vía `ui/widgets.js` |

### Instalación en Urano

**Dev Mode:** MCP Manager → Desarrollador → Vincular Carpeta → selecciona `urano-charts/`. Luego `npm run deploy` (o al menos `build:ui`).

**ZIP:** `npm install` → `npm run deploy` → `npm run urano-launch` → Instalar MCP (`.zip`).

No hay settings de secrets: al instalar, ya está listo.

### Flujo demo (humano)

1. Instala / Dev Link el pack y Forzar Recarga skills (o reinicia Desktop).
2. En el chat: *“Corre demo_uispec de urano-charts y renderiza el uiSpec.”*
3. Deberías ver TimeSeries + BoxPlot + Parallel (no `UNKNOWN_TYPE`).
4. Para datos reales: builder correspondiente → `urano_render_json` (`waitForAction: false`).

### Flujo típico (builder → render)

```mermaid
flowchart LR
  A[list_chart_types] --> B{Tipo}
  B -->|nativo| C[Chart / Dashboard host]
  B -->|pack| D[build_*_uispec]
  D --> E[uiSpec charts.*]
  E --> F[urano_render_json]
  F --> G[Host carga ui/widgets.js]
  G --> H[TimeSeries / BoxPlot / Parallel]
```

### Avisos importantes

- **No** overridees `type: "Chart"` / `Dashboard` con este pack.
- Si el lint dice `UNKNOWN_TYPE`, el catálogo no sincronizó: `npm run deploy` + reload skills (ver `SKILL.md`).
- Preferir Chart nativo para tipos ya soportados.

---

## 2. Descripción técnica

### Arquitectura

- MCP nativo: `mcpServer.command: 'native'`.
- Sin Engine Plugin (v1).
- `inDesktop: true`, `inCloud: true` (UI pura, sin FS local obligatorio).
- Widgets React empaquetados en IIFE; React viene del host (`window.__URANO_JSONLIVE__`).
- Deps UI: **uPlot** (MIT), **Apache ECharts** (Apache-2.0) — bundladas en el IIFE.

### Estructura (de dónde sale cada archivo)

```text
urano-charts/
├── config.ts                 # manifiesto + jsonLiveWidgets + pluginSchemas  (tú lo escribes)
├── SKILL.md                  # protocolo del agente                          (tú lo escribes)
├── README.md / LICENSE
├── package.json              # scripts build:ui / deploy / urano-launch
├── scripts/
│   └── build-ui.js           # esbuild IIFE → genera widgets.js             (tú lo copias/adaptas)
├── ui/
│   ├── src/
│   │   ├── index.ts          # exporta TimeSeries, BoxPlot, Parallel        (tú)
│   │   ├── TimeSeries.tsx    # componente React                             (tú)
│   │   ├── BoxPlot.tsx
│   │   └── Parallel.tsx
│   ├── shims/
│   │   ├── react.ts          # bridge a React del host                      (tú / molde climate)
│   │   └── jsx-runtime.ts
│   └── widgets.js            # ★ GENERADO — no editar a mano
├── Plugins/
│   └── Charts/ChartsPlugin.ts  # tools build_*_uispec                       (tú)
├── config.js                 # ★ GENERADO (copia de dist/config.js en deploy)
└── dist/                     # ★ GENERADO — contenido del ZIP
    ├── config.js
    ├── Plugins/Charts/ChartsPlugin.js
    └── ui/widgets.js
```

### Tools MCP (Charts)

| Tool | Rol |
|------|-----|
| `list_chart_types` | Nativo vs pack; licencias; sin keys |
| `build_timeseries_uispec` | Valida labels/series → uiSpec `charts.TimeSeries` |
| `build_boxplot_uispec` | categories + values raw → `charts.BoxPlot` |
| `build_parallel_uispec` | dimensions + rows → `charts.Parallel` |
| `demo_uispec` | Smoke test (`which`: all \| timeseries \| boxplot \| parallel) |

Flujo: **builder → `urano_render_json`** (`purpose` + `uiSpec`, `waitForAction: false`).

### Widgets JsonLive

| Type | Export | Props clave |
|------|--------|-------------|
| `charts.TimeSeries` | `TimeSeries` | `labels[]`, `series: number[][]`, `seriesNames?`, `height?` |
| `charts.BoxPlot` | `BoxPlot` | `categories[]`, `values: number[][]` (raw), `height?` |
| `charts.Parallel` | `Parallel` | `dimensions[{name,min?,max?}]`, `rows: number[][]`, `height?` |

Declarados en `config.ts` → `jsonLiveWidgets[]` (type, bundle, exportName, aliases, propsHint).

### Parámetros STRING JSON

```json
{
  "title": "Temperatura",
  "labelsJson": "[\"Lun\",\"Mar\",\"Mié\"]",
  "seriesJson": "[[18,20,19],[10,12,11]]",
  "seriesNamesJson": "[\"Max\",\"Min\"]",
  "height": "320"
}
```

### Build

```bash
npm install
npm run build:ui        # solo IIFE → dist/ui/widgets.js + copia a ui/widgets.js
npm run deploy          # build:ui + esbuild backend + copia config.js a raíz
npm run urano-launch    # ZIP desde dist/
```

Dev Mode: linkea la carpeta + `npm run build:ui:watch` (hot reload UI).

### Anti-contexto

- No pedir API keys.
- No inventar types `charts.*` fuera de los tres registrados.
- Arrays a tools como **STRING JSON**.
- Skill-First: protocolo en `SKILL.md`.

### Referencia de patrón

- Pack molde widgets: `urano-climate` (`DemoBadge`) y este pack.
- Docs host: `UranoDesktop/docs/CREATE_MCP_GUIDE.md` §8 · `RENDER_GUIDE.md` · `DEV_MODE.md` (`HOT_RELOAD_UI`).

---

## 3. Cómo crear un plugin de widgets JsonLive (solo lo específico)

Esto es **lo que cambia** respecto a un MCP normal (tools + `SKILL.md`). El resto (config, Plugins, deploy backend) es igual.

### 1. Fuentes que escribes tú

| Archivo | Rol |
|---------|-----|
| `ui/src/MiWidget.tsx` | Componente React. Contrato: `({ props, children, tabId }) => …` |
| `ui/src/index.ts` | `export { MiWidget } from './MiWidget'` |
| `ui/shims/react.ts` | Lee `window.__URANO_JSONLIVE__.React` (sin segunda copia de React) |
| `ui/shims/jsx-runtime.ts` | Lee `jsx` / `jsxs` del host |
| `scripts/build-ui.js` | esbuild: entry `ui/src/index.ts` → IIFE |
| `config.ts` → `jsonLiveWidgets` | Declara `type`, `bundle: 'ui/widgets.js'`, `exportName` |
| `SKILL.md` | Ejemplos `urano_render_json` con tu `type` |

### 2. De dónde sale `widgets.js` (no se escribe a mano)

```text
ui/src/*.tsx  +  shims  +  npm deps (uplot, echarts, …)
        │
        ▼  npm run build:ui   (scripts/build-ui.js → esbuild)
        │
        ├─► dist/ui/widgets.js     (artefacto para ZIP)
        └─► ui/widgets.js          (copia para Dev Link / catálogo)
```

El script:

1. Empaqueta todo en un **IIFE** browser (`format: 'iife'`).
2. Pone el global `__UranoMcpWidgetExports` con tus exports (`TimeSeries`, …).
3. Alias `react` / `react/jsx-runtime` → shims del host.
4. Añade un **footer** que llama `window.__URANO_JSONLIVE__.acceptBundle(...)`.
5. Escribe `dist/ui/widgets.js` y copia a `ui/widgets.js`.

Si editas solo el `.tsx` y no corres `build:ui`, el host sigue sirviendo el IIFE viejo.

### 3. Cómo el host lo usa

1. Al cargar skills, Desktop lee `config.jsonLiveWidgets` y registra los types (lint deja de marcar `UNKNOWN_TYPE`).
2. `urano_render_json` con `type: "charts.TimeSeries"` → Front pide el catálogo → carga `urano-mcp-ui://urano-charts/ui/widgets.js` (o HTTP en Cloud).
3. El IIFE se ejecuta, `acceptBundle` registra el componente, JsonLive lo pinta.

### 4. Reglas duras del bundle

- Prohibido: `electron`, `fs`, Node APIs, segunda copia de React, fetch a orígenes no controlados.
- Types **namespaced** (`mymodule.MiWidget`). No puedes overridear `Chart` / `Dashboard`.
- ZIP: `deploy` debe dejar `dist/ui/widgets.js`; `urano-launch` lo empaqueta como `ui/widgets.js` en el zip.

### 5. Checklist mínimo

1. Scaffold MCP normal (`config.ts`, `Plugins/…`, `SKILL.md`).
2. Añadir `ui/` + shims + `scripts/build-ui.js`.
3. Declarar `jsonLiveWidgets`.
4. `npm run build:ui` → verificar que existen `ui/widgets.js` y `dist/ui/widgets.js`.
5. Dev Link o ZIP → `demo` / `urano_render_json` con tu type.

---

## 4. Créditos

| | |
|--|--|
| **Pack** | urano-charts |
| **Licencia** | MIT — ver [LICENSE](./LICENSE) |
| **Deps UI** | [uPlot](https://github.com/leeoniya/uPlot) (MIT) · [Apache ECharts](https://echarts.apache.org/) (Apache-2.0) |
| **Runtime** | UranoDesktop / Cloud · MCP nativo + JsonLive widgets |
| **Molde** | `urano-climate` (`ui/` + `build-ui.js`) |

Hecho para demostrar gráficas avanzadas **locales, gratis y sin keys**, como extensión del render JsonLive.