--- name: create_chrome_profile kind: function lang: bash domain: browser version: "1.0.0" purity: impure signature: "create_chrome_profile --user-data-dir --profile --name [--port N] [--chrome-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\":\"\",\"name\":\"\",\"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) |