---
name: sync_chromium_profiles_to_rofi
kind: function
lang: py
domain: infra
version: "1.0.0"
purity: impure
signature: "sync_chromium_profiles_to_rofi(local_state_path: str = '', apps_dir: str = '', icons_dir: str = '', chromium_cmd: str = 'chromium') -> dict"
description: "Sincroniza los perfiles de Chromium con el lanzador (rofi / menus .desktop). Lee profile.info_cache del Local State y por cada perfil de usuario valido genera un avatar PNG con las iniciales (o reutiliza la foto Gaia) y un archivo .desktop que lanza Chromium en ese perfil con su icono. Limpia los .desktop obsoletos generados por esta funcion (marcador X-RofiChromiumProfile) y refresca la base de datos de aplicaciones con update-desktop-database (best-effort). Excluye System Profile y perfiles con nombre vacio. Idempotente."
tags: ["rofi", "chromium", "desktop", "launcher", "xdg", "profiles", "icons"]
params:
  - name: local_state_path
    desc: "Ruta al archivo 'Local State' de Chromium (JSON con profile.info_cache). Si viene vacio usa ~/.config/chromium-cdp/Local State. El user-data-dir se deriva como su dirname."
  - name: apps_dir
    desc: "Directorio XDG de salida de los .desktop. Si viene vacio usa ~/.local/share/applications. rofi escanea este arbol."
  - name: icons_dir
    desc: "Directorio de salida de los iconos PNG por perfil. Si viene vacio usa ~/.local/share/icons/chromium-profiles."
  - name: chromium_cmd
    desc: "Comando base para el Exec del .desktop. Default 'chromium'. NO se pasa --user-data-dir: el wrapper del sistema (/etc/chromium.d/cdp) lo inyecta. El --profile-directory es relativo a ese user-data-dir."
output: "dict con user_data_dir (str absoluto), created (lista de .desktop escritos), removed (lista de .desktop obsoletos borrados), profiles (lista de {dir, name, desktop, icon}), warnings (perfiles saltados por datos raros) y update_desktop_database ({attempted, ok, detail})."
uses_functions:
  - generate_initials_avatar_py_infra
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports:
  - Pillow
file_path: "python/functions/infra/sync_chromium_profiles_to_rofi.py"
tested: false
tests: []
test_file_path: ""
---

## Ejemplo

```bash
# Ejecucion directa con defaults (lee ~/.config/chromium-cdp/Local State,
# escribe .desktop en ~/.local/share/applications y PNGs en
# ~/.local/share/icons/chromium-profiles)
cd $HOME/fn_registry
./fn run sync_chromium_profiles_to_rofi_py_infra
```

```python
# Variante Python importando la funcion (PYTHONPATH=python/functions via fn run,
# o sys.path.insert al ejecutar suelto).
import sys
sys.path.insert(0, "python/functions")
from infra.sync_chromium_profiles_to_rofi import sync_chromium_profiles_to_rofi

# Apuntando a un Local State y directorios de salida de prueba en /tmp
res = sync_chromium_profiles_to_rofi(
    local_state_path="/tmp/chromium-test/Local State",
    apps_dir="/tmp/chromium-test/apps",
    icons_dir="/tmp/chromium-test/icons",
)
print(res["created"], res["removed"])
```

## Cuando usarla

Tras crear, renombrar o eliminar un perfil de Chromium, o a diario via dag_engine,
para que los perfiles aparezcan en rofi (y en cualquier menu XDG) con su propio
icono y un Exec que abre Chromium directamente en ese perfil. Util tambien al
provisionar una maquina nueva donde se han clonado varios perfiles.

## Gotchas

- El `Exec` del `.desktop` depende del wrapper del sistema que inyecta
  `--user-data-dir=$HOME/.config/chromium-cdp` (via `/etc/chromium.d/cdp`). Por eso
  NO se pasa `--user-data-dir` aqui; solo `chromium --profile-directory="<dir>"`. En
  una maquina sin ese wrapper el `.desktop` abriria el perfil del user-data-dir por
  defecto de Chromium, no el del directorio `chromium-cdp`.
- El marcador `X-RofiChromiumProfile=true` gobierna la limpieza: la funcion solo
  borra `.desktop` que ella misma genero. NUNCA toca `.desktop` ajenos aunque
  coincidan con el patron `chromium-*.desktop`.
- `update-desktop-database` es best-effort: si el binario no esta en el PATH, la
  funcion NO falla; lo reporta en `update_desktop_database.detail`. rofi suele
  funcionar igualmente sin el refresh, pero algunos menus cachean.
- Excluye siempre `"System Profile"` (no es un perfil de usuario) y cualquier
  entrada con `name` vacio.
- Si un perfil tiene `gaia_picture_file_name` y el archivo existe en el dir del
  perfil, se usa esa imagen tal cual como icono (sin recorte circular). Si no, se
  genera el avatar de iniciales con `generate_initials_avatar`.
- El `slug` se deriva de la CLAVE del `info_cache` (el nombre del subdirectorio,
  ej. `"Profile 1"` -> `profile-1`), no del nombre legible. Asi dos perfiles con el
  mismo nombre visible pero distinto directorio no colisionan.
