---
name: create_chrome_profile
kind: function
lang: bash
domain: browser
version: "1.0.0"
purity: impure
signature: "create_chrome_profile --user-data-dir <dir> --profile <dir-name> --name <legible> [--port N] [--chrome-path <path>] [--no-launch] [--timeout-sec N] [--dry-run]"
description: "Crea un perfil Chrome/Chromium nuevo en un user-data-dir: opcionalmente lanza chromium headless vía systemd-run para que la managed policy instale las extensiones forzadas (uBlock, web_proxy) y luego edita Local State para asignar el nombre legible al perfil. Con --no-launch crea solo la estructura de carpetas y la entrada en Local State sin arrancar Chrome."
tags: [navegator, chromium, profile, browser, cdp, headless, scraping]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: []
tested: false
tests: []
test_file_path: ""
file_path: "bash/functions/browser/create_chrome_profile.sh"
params:
  - name: --user-data-dir
    desc: "Raíz del user-data-dir de Chrome/Chromium. Puede no existir; la función lo crea. Obligatorio."
  - name: --profile
    desc: "Nombre de la carpeta del perfil dentro de user-data-dir, por ejemplo: Default, \"Profile 1\", Automation. Obligatorio."
  - name: --name
    desc: "Nombre legible visible en el selector de perfil de Chrome, por ejemplo: Work, Aurgi, Bot. Obligatorio."
  - name: --port
    desc: "Puerto CDP para el lanzamiento headless. Default: 9250. Usar un valor distinto al 9222 global para no colisionar."
  - name: --chrome-path
    desc: "Ruta absoluta al binario chromium/chrome. Si se omite, auto-detecta: chromium, chromium-browser, google-chrome, brave-browser."
  - name: --no-launch
    desc: "No lanza chromium. Solo crea la carpeta del perfil y edita Local State con el nombre legible. El perfil no tendrá extensiones instaladas. Útil para tests y CRUD offline."
  - name: --timeout-sec
    desc: "Segundos máximos esperando a que Preferences aparezca tras el lanzamiento headless. Default: 25."
  - name: --dry-run
    desc: "Describe las acciones que se ejecutarían sin lanzar ni escribir nada. Emite el JSON de resultado con dry_run:true."
output: "JSON en stdout: {\"profile\":\"<dir-name>\",\"name\":\"<legible>\",\"launched\":true|false,\"preferences_created\":true|false}. En dry-run añade \"dry_run\":true. Exit 0 en éxito."
---

## Ejemplo

```bash
source $HOME/fn_registry/bash/functions/browser/create_chrome_profile.sh

# Modo offline (no lanza Chrome, solo CRUD de Local State — seguro para tests)
create_chrome_profile \
  --user-data-dir /tmp/test_udd \
  --profile "Automation" \
  --name "Aurgi Bot" \
  --no-launch
# Salida: {"profile":"Automation","name":"Aurgi Bot","launched":false,"preferences_created":false}

# Modo normal: lanza headless para que la policy instale uBlock y web_proxy,
# luego asigna nombre en Local State
create_chrome_profile \
  --user-data-dir "$HOME/.local/share/web_scraping/profiles" \
  --profile "Profile 1" \
  --name "Work" \
  --port 9250
# Salida: {"profile":"Profile 1","name":"Work","launched":true,"preferences_created":true}

# Dry-run: describe acciones sin ejecutar nada
create_chrome_profile \
  --user-data-dir "$HOME/.local/share/web_scraping/profiles" \
  --profile "Default" \
  --name "Scraping" \
  --dry-run
```

## Cuando usarla

Úsala para aprovisionar perfiles nuevos en un user-data-dir de automatización antes de lanzar sesiones CDP con `script-navegador` o funciones del grupo `navegator`. En modo normal (sin `--no-launch`) la managed policy instala automáticamente uBlock y la extensión web_proxy en el perfil nuevo; en `--no-launch` sirve para tests unitarios o para crear la entrada de Local State sin depender de Chrome.

## Gotchas

- **Lanzar chromium desde Bash tool de Claude da exit-144**: la función usa `systemd-run --user --collect` para aislar el proceso en su propio cgroup, evitando que el harness del agente lo mate. Esto es obligatorio; lanzar con `&` / `setsid` daría exit-144 en el contexto del agente.
- **La managed policy instala las extensiones al arrancar el perfil**: NO pasar `--disable-extensions` — rompería la forcelist. Las extensiones force-listed (`ExtensionInstallForcelist` en `/etc/chromium/policies/managed/extensions.json`) se instalan en el perfil durante el primer arranque; en el headless inicial puede no completar la descarga si no hay red o si el timeout es corto.
- **Dos chromium NO pueden compartir el mismo user-data-dir**: si ya hay un chromium corriendo sobre `--user-data-dir`, la función detecta `SingletonLock` y sale con exit 2 antes de lanzar. Para perfiles de automatización paralela, usa un `--user-data-dir` dedicado por perfil.
- **Local State debe editarse con Chrome muerto**: la función para el unit de systemd y espera la desaparición de `SingletonLock` antes de editar `Local State`. Si se edita mientras Chrome está vivo, Chrome sobreescribe el archivo desde memoria al salir y los cambios de nombre se pierden.
- **`--remote-allow-origins=*` necesita comillas en zsh**: el glob `*` se expande si no va entre comillas. La función pasa el flag correctamente internamente, pero si lo pasas tú en otros scripts acuérdate de las comillas.
- **Perfil diario en `~/.config/chromium-cdp`**: en este equipo el fragmento `/etc/chromium.d/cdp` redirige el user-data-dir global a `~/.config/chromium-cdp`. Para automatización usar siempre un `--user-data-dir` dedicado fuera de `~/.config/`.
- **Timeout corto puede dar `preferences_created: false`**: el perfil headless tarda entre 2-8 segundos en crear `Preferences` según la carga del sistema. Si se aumenta `--timeout-sec` a 45-60 en máquinas lentas se evitan falsos timeouts.

## Exit codes

| Código | Significado |
|--------|------------|
| 0 | Éxito |
| 1 | Argumento obligatorio faltante o binario no encontrado |
| 2 | Lock: ya hay un chromium usando el mismo user-data-dir |
| 3 | Timeout esperando a que Preferences se cree |
| 4 | Error editando Local State (JSON inválido tras escritura) |
