Skip to main content
📝 Aplicaciones Laravel

Laravel Prompts v0.3.15: Las Primitivas CLI Que Necesitabas

Laravel Prompts v0.3.15: Las Primitivas CLI Que Necesitabas Estaba a mitad de construir un comando de despliegue para el proyecto de un cliente la sem...

25 min

Tiempo de lectura

4,956

Palabras

Mar 18, 2026

Publicado

Engr Mejba Ahmed

Escrito por

Engr Mejba Ahmed

Compartir Artículo

Laravel Prompts v0.3.15: Las Primitivas CLI Que Necesitabas

Laravel Prompts v0.3.15: Las Primitivas CLI Que Necesitabas

Estaba a mitad de construir un comando de despliegue para el proyecto de un cliente la semana pasada cuando me topé con el muro que todo desarrollador Laravel conoce demasiado bien. El comando necesitaba ejecutar seis operaciones secuenciales: instalar dependencias, compilar assets, ejecutar migraciones, limpiar cachés, precalentar rutas y hacer ping a un health check. Cada paso tomaba entre 3 y 45 segundos. ¿Y mi experiencia de usuario para todo eso? Un cursor parpadeante. Quizás una llamada a $this->info() entre pasos si estaba de humor generoso.

La terminal simplemente se quedaba ahí. En silencio. El tipo de silencio que te hace preguntarte si el proceso se colgó, si deberías presionar Ctrl+C y empezar de nuevo, o si la migración de base de datos realmente está procesando 200,000 filas y solo necesitas esperar.

Entonces vi las notas de la versión v0.3.15 publicadas el 17 de marzo de 2026. Cinco nuevas primitivas. Todas extraídas del CLI de Laravel Cloud — las herramientas internas que el equipo de Laravel construyó para gestionar despliegues en la nube. La función estrella es task(), y resuelve exactamente el problema que acabo de describir. Pero el elenco de apoyo — stream(), notify(), autocomplete() y title() — llena vacíos que no me había dado cuenta de que llevaba años sorteando.

Despejé mi tarde y reescribí ese comando de despliegue. Aquí está todo lo que encontré.

Por Qué Existen Estas Primitivas — Y Por Qué Llegaron Ahora

La historia detrás importa porque explica por qué estas funcionalidades se sienten tan pulidas desde el inicio.

Cuando el equipo de Laravel construyó el Cloud CLI — la herramienta de línea de comandos que gestiona toda tu infraestructura de Laravel Cloud — necesitaban interacciones de terminal que fueran mucho más allá de "hacer una pregunta, obtener una respuesta". Los despliegues en la nube involucran procesos de larga duración con salida de logs en tiempo real. Necesitan spinners que actualicen sus etiquetas a medida que el contexto cambia. Necesitan mensajes de estado (éxito, advertencia, error) que persistan en pantalla mientras los logs con scroll fluyen debajo. Necesitan texto en streaming para operaciones asistidas por IA. Necesitan notificaciones de escritorio cuando un despliegue de 10 minutos termina mientras estás en otra ventana.

Nada de eso existía en Laravel Prompts antes. Así que lo construyeron internamente. Y con v0.3.15, extrajeron esas primitivas de vuelta al paquete mismo — probadas en batalla tras meses de uso real dentro del Cloud CLI.

Ese patrón de extracción es una de las cosas que más respeto del ecosistema Laravel. Las funcionalidades no llegan como APIs teóricas. Llegan porque alguien las necesitó en producción, las construyó bajo presión, las refinó a través del uso diario, y luego las generalizó para todos los demás. La función task() no empezó como un documento de especificaciones. Empezó como una pantalla de despliegue que necesitaba mantener informados a los ingenieros durante builds de 5 minutos.

Con más de 179 millones de instalaciones en Packagist y 535 paquetes dependientes, los cambios en Laravel Prompts repercuten en todo el ecosistema PHP. Esta versión no es un parche menor — es una expansión fundamental de lo que es posible en la interfaz de terminal para aplicaciones PHP.

Esto es lo que realmente se incluyó.

La Función task() — Los Procesos Largos Finalmente Tienen una UI Real

Este es el pilar central de v0.3.15, y con buena razón. La función task() te da un spinner que se actualiza en vivo, salida de logs con scroll, mensajes de estado estables que persisten en pantalla, y la capacidad de actualizar la etiqueta a medida que la tarea progresa. Todo desde una sola llamada a función.

Aquí está la firma básica:

use function Laravel\Prompts\task;

task(
    title: 'Deploying application',
    callback: function ($task) {
        $task->log('Pulling latest changes...');
        // ... actual work ...

        $task->label('Compiling assets');
        $task->log('Running npm build...');
        // ... more work ...

        $task->succeed('Deployment complete');
    }
);

Qué sucede cuando esto se ejecuta: un spinner se anima junto a "Deploying application." A medida que tu callback se ejecuta, cada llamada a $task->log() escribe una línea en un área de salida con scroll debajo del spinner. El área de log hace scroll automáticamente — las líneas antiguas suben mientras llegan las nuevas, manteniendo visible la salida más reciente. El spinner sigue animándose todo el tiempo, para que el usuario siempre sepa que el proceso está vivo.

La llamada $task->label() es sutil pero poderosa. Cambia el texto junto al spinner sin interrumpir el scroll del log. Así puedes mostrar "Pulling dependencies" para la primera fase, "Compiling assets" para la segunda, "Running migrations" para la tercera — todo mientras la salida detallada del log fluye debajo. Dos niveles de densidad de información: la etiqueta te dice en qué fase estás, el log te dice qué está pasando ahora mismo.

Mensajes de Estado Que Permanecen

La parte que me convenció: mensajes de estado estables.

task(
    title: 'Running test suite',
    callback: function ($task) {
        $task->log('PHPUnit 11.5.2 — 342 tests');

        // Tests run...
        $task->log('Passed: UserRegistrationTest (0.234s)');
        $task->log('Passed: PaymentProcessingTest (1.203s)');

        // A warning surfaces
        $task->warning('3 tests marked as risky');

        // More tests...
        $task->log('Passed: ApiEndpointTest (0.089s)');

        $task->succeed('342 tests passed');
    }
);

Cuando llamas a $task->warning(), ese mensaje se renderiza encima del área de log con scroll como una línea resaltada y persistente. No se desplaza fuera de vista. Se queda fijado en la parte superior mientras el resto del log continúa fluyendo debajo. Mismo comportamiento para $task->error(). Y $task->succeed() finaliza la tarea con una marca de verificación verde y tu mensaje, reemplazando el spinner.

Esto resuelve un problema que he parchado durante años: información importante de estado que se pierde en una salida verbosa. En un comando de migración, la advertencia "3 tablas serán eliminadas" no debería desplazarse y perderse en una pared de sentencias SQL. Debería quedarse fija. Ahora lo hace.

El Requisito de PCNTL

Algo que debes saber: la animación del spinner requiere la extensión PHP pcntl. En macOS y la mayoría de distribuciones Linux, está disponible por defecto. En Windows (sin WSL), la extensión PCNTL no está disponible — obtendrás una versión estática de respaldo en su lugar. La tarea sigue funcionando, el log sigue produciendo salida, pero el spinner no se animará.

Verifica si la tienes:

php -m | grep pcntl

Si estás construyendo comandos Artisan que necesitan ejecutarse multiplataforma, diseña tu salida para que sea útil incluso sin la animación. La función task() maneja esto con elegancia — no necesitas escribir código condicional.

Mi Comando de Despliegue, Reconstruido

Así es como se ve mi comando de despliegue ahora versus antes. La diferencia en experiencia de usuario es dramática.

Antes (la era oscura):

public function handle()
{
    $this->info('Starting deployment...');

    // Pull code
    $this->call('down');
    $output = shell_exec('git pull origin main 2>&1');
    $this->info('Code pulled.');

    // Install dependencies
    $output = shell_exec('composer install --no-dev 2>&1');
    $this->info('Dependencies installed.');

    // Compile assets
    $output = shell_exec('npm run build 2>&1');
    $this->info('Assets compiled.');

    // Migrate
    $this->call('migrate', ['--force' => true]);
    $this->info('Migrations complete.');

    $this->call('up');
    $this->info('Done!');
}

¿Funcional? Claro. Pero el usuario no ve nada durante 30 segundos seguidos, luego un estallido de texto estático. Sin indicación de progreso durante cada paso. Sin distinción entre "todo está bien" y "algo falló pero seguimos adelante."

Después (v0.3.15):

use function Laravel\Prompts\task;
use function Laravel\Prompts\notify;
use function Laravel\Prompts\title;

public function handle()
{
    title('Deploy: production');

    task(
        title: 'Deploying to production',
        callback: function ($task) {
            $task->label('Pulling latest code');
            $task->log('Running git pull origin main...');

            $gitOutput = [];
            $gitCode = 0;
            exec('git pull origin main 2>&1', $gitOutput, $gitCode);

            foreach ($gitOutput as $line) {
                $task->log($line);
            }

            if ($gitCode !== 0) {
                $task->error('Git pull failed — aborting deployment');
                return;
            }

            $task->label('Installing dependencies');
            $task->log('Running composer install --no-dev...');
            exec('composer install --no-dev 2>&1', $composerOutput);

            foreach ($composerOutput as $line) {
                $task->log($line);
            }

            $task->label('Compiling assets');
            $task->log('Running npm build...');
            exec('npm run build 2>&1', $npmOutput);

            $task->label('Running migrations');
            $task->log('Applying pending migrations...');
            Artisan::call('migrate', ['--force' => true]);
            $task->log('Migrations applied.');

            $task->label('Clearing caches');
            Artisan::call('cache:clear');
            Artisan::call('config:clear');
            Artisan::call('route:clear');
            $task->log('All caches cleared.');

            $task->label('Warming caches');
            Artisan::call('config:cache');
            Artisan::call('route:cache');
            $task->log('Caches warmed.');

            $task->succeed('Deployment complete — all systems operational');
        }
    );

    title('Deploy: complete');

    notify(
        title: 'Deployment Complete',
        body: 'Production deployment finished successfully.'
    );
}

La terminal ahora muestra un indicador giratorio durante cada fase, la etiqueta se actualiza a medida que el comando avanza por las etapas, cada línea de salida real de git, Composer y npm fluye en el log con scroll, los errores aparecen inmediatamente como mensajes de estado fijados, y cuando termina, aparece una notificación nativa de escritorio. Esa última parte — la notificación — nos lleva a la siguiente primitiva.

notify() — Notificaciones Nativas de Escritorio Desde PHP

Esta me sorprendió. No porque las notificaciones de escritorio sean un concepto novedoso, sino porque nunca las esperé de una herramienta CLI de PHP.

use function Laravel\Prompts\notify;

notify(
    title: 'Build Complete',
    body: 'Your application has been compiled and deployed.'
);

Eso es todo. Aparece una notificación nativa del sistema operativo — del mismo tipo que recibes de Slack, VS Code o tu cliente de correo. En macOS, usa el centro de notificaciones del sistema. En Linux, funciona a través del demonio de notificaciones estándar. En Windows con WSL, se conecta con las notificaciones de Windows.

El caso de uso que inmediatamente me hizo clic: comandos Artisan de larga duración que lanzo y olvido. Inicio un seed de base de datos que toma 8 minutos, cambio a mi editor, empiezo a trabajar en otra cosa, y me olvido completamente de la terminal. Veinte minutos después me pregunto "¿habrá terminado?" y tengo que ir a verificar.

Ahora agrego una línea al final del comando. La notificación me encuentra donde sea que esté.

public function handle()
{
    // ... 8 minutes of seeding ...

    notify(
        title: 'Database Seeded',
        body: sprintf('%d records created in %d seconds.', $count, $elapsed)
    );
}

Algo pequeño. Pero las cosas pequeñas que eliminan carga cognitiva se acumulan en una experiencia de desarrollo genuinamente mejor.

stream() — Texto Que Se Escribe Solo en la Terminal

Si task() es el caballo de batalla de esta versión, stream() es la pieza de exhibición. Muestra texto que fluye en la terminal carácter por carácter (o fragmento por fragmento), con un efecto gradual de aparición.

use function Laravel\Prompts\stream;

$stream = stream('Processing analysis');

$stream->append('Analyzing codebase structure... ');
$stream->append("found 342 files.\n");
$stream->append('Identifying patterns... ');
$stream->append("detected 12 architectural concerns.\n");
$stream->append('Generating recommendations...');

$stream->close();

El método append() agrega texto con un efecto visual de aparición progresiva — los caracteres se materializan gradualmente en lugar de aparecer todos de golpe. Esto podría sonar como un truco hasta que consideras el caso de uso principal: mostrar contenido generado por IA en la terminal.

Si estás construyendo comandos Artisan que llaman a OpenAI, Anthropic, o cualquier otra API de LLM con respuestas en streaming, stream() te da el mismo efecto de máquina de escribir que ves en la interfaz de ChatGPT — pero en tu terminal. El texto llega a medida que el modelo lo genera, y stream() lo renderiza con esa satisfactoria revelación progresiva.

use function Laravel\Prompts\stream;
use OpenAI\Laravel\Facades\OpenAI;

$stream = stream('AI Analysis');

$response = OpenAI::chat()->createStreamed([
    'model' => 'gpt-4o',
    'messages' => [
        ['role' => 'user', 'content' => 'Analyze this error log...'],
    ],
]);

foreach ($response as $chunk) {
    $text = $chunk->choices[0]->delta->content ?? '';
    $stream->append($text);
}

$stream->close();

El método close() finaliza la salida, restaura el cursor y señala que el streaming está completo. Sin él, la terminal quedaría en un estado indeterminado.

Ya puedo ver cómo esto se convertirá en estándar en los comandos Artisan potenciados por IA — el tipo de herramientas que rápidamente se están volviendo normales en las aplicaciones Laravel desde que el ecosistema adoptó las integraciones de IA a lo largo de 2025 y hasta 2026. Tener una primitiva de renderizado de primera mano para texto en streaming es exactamente el soporte fundamental que el paquete necesitaba.

autocomplete() — Texto Fantasma en la Terminal

La función autocomplete() agrega autocompletado en línea a las entradas de texto, mostrando sugerencias como texto fantasma que el usuario puede aceptar con Tab o la tecla de flecha derecha.

use function Laravel\Prompts\autocomplete;

$framework = autocomplete(
    label: 'Which framework?',
    options: fn (string $value) => collect([
        'Laravel', 'Symfony', 'Slim', 'Lumen', 'CakePHP',
    ])
        ->filter(fn ($item) => str_contains(
            strtolower($item),
            strtolower($value)
        ))
        ->values()
        ->all()
);

Escribe "la" y "Laravel" aparece como texto fantasma desvanecido después de tu cursor. Presiona Tab para aceptarlo. Si sigues escribiendo "lum," el texto fantasma cambia a "Lumen." El callback de opciones recibe el valor de entrada actual y devuelve sugerencias coincidentes en tiempo real.

La diferencia entre autocomplete() y la función existente suggest() es el modelo de interacción. suggest() muestra una lista desplegable de opciones coincidentes debajo de la entrada. autocomplete() muestra texto fantasma en línea — el mismo patrón que conoces de GitHub Copilot, tu IDE, o las barras de direcciones de navegadores modernos. Es más rápido para usuarios experimentados que saben lo que quieren y solo necesitan que el sistema termine su pensamiento.

¿Cuándo deberías usar cada uno?

  • suggest() funciona cuando el usuario está explorando opciones y necesita ver múltiples coincidencias simultáneamente
  • autocomplete() funciona cuando el usuario sabe aproximadamente la respuesta y quiere velocidad — menos teclas, flujo más rápido

Para comandos que desarrolladores experimentados ejecutan a diario — seleccionar entornos, elegir ramas, especificar nombres de modelos — autocomplete() se sentirá notablemente más ágil que suggest().

title() — Establece el Título de la Ventana de Terminal

Este es engañosamente simple:

use function Laravel\Prompts\title;

title('Application Installer');

Cambia el título de la ventana o pestaña de la terminal. Eso es todo. El texto en la barra de título de tu terminal o la etiqueta de la pestaña se actualiza a cualquier cadena que pases.

¿Por qué importa esto? Porque cualquiera que ejecute más de tres pestañas de terminal simultáneamente conoce el dolor de buscar la correcta. Si tu comando Artisan establece el título como "Deploying: staging" o "Queue Worker: emails" o "Migrating: production," encontrar la pestaña correcta se vuelve instantáneo.

Combínalo con notify() para comandos de larga duración:

title('Deploy: production');

task(
    title: 'Running deployment',
    callback: function ($task) {
        // ... deployment steps ...
        $task->succeed('All clear');
    }
);

title('Deploy: complete');

notify(
    title: 'Production Deploy',
    body: 'Finished at ' . now()->format('H:i:s')
);

La pestaña de la terminal te dice el estado de un vistazo. La notificación te trae de vuelta cuando estás en otra parte. Dos primitivas, y tu comando de despliegue respeta tu atención en lugar de exigirla.

Poniéndolo Todo Junto — Un Comando del Mundo Real

Las primitivas individuales son interesantes. Combinadas, son transformadoras. Aquí hay un comando Artisan completo que usa cada nueva funcionalidad de v0.3.15 — el tipo de comando que realmente podrías construir para un flujo de trabajo en producción:

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use function Laravel\Prompts\autocomplete;
use function Laravel\Prompts\task;
use function Laravel\Prompts\stream;
use function Laravel\Prompts\notify;
use function Laravel\Prompts\title;
use function Laravel\Prompts\info;

class AnalyzeCodebase extends Command
{
    protected $signature = 'analyze {--fix}';
    protected $description = 'Run AI-powered codebase analysis';

    public function handle()
    {
        title('Codebase Analysis');

        $scope = autocomplete(
            label: 'What should I analyze?',
            options: fn (string $value) => collect([
                'Full codebase',
                'Controllers only',
                'Models only',
                'Routes and middleware',
                'Database migrations',
                'Test coverage',
            ])
                ->filter(fn ($item) => str_contains(
                    strtolower($item),
                    strtolower($value)
                ))
                ->values()
                ->all()
        );

        // Phase 1: Scan with task()
        $results = [];

        task(
            title: 'Scanning codebase',
            callback: function ($task) use ($scope, &$results) {
                $task->label('Discovering files');
                $task->log("Scope: {$scope}");

                $files = $this->discoverFiles($scope);
                $task->log(count($files) . ' files found.');

                $task->label('Analyzing patterns');

                foreach ($files as $file) {
                    $task->log("Scanning: {$file}");
                    $results[] = $this->analyzeFile($file);
                }

                $issues = collect($results)->where('has_issues', true);

                if ($issues->count() > 10) {
                    $task->warning($issues->count() . ' files with issues detected');
                }

                $task->succeed(
                    count($files) . ' files scanned, '
                    . $issues->count() . ' issues found'
                );
            }
        );

        // Phase 2: AI analysis with stream()
        $analysis = stream('Generating recommendations');

        foreach ($this->getAiAnalysis($results) as $chunk) {
            $analysis->append($chunk);
        }

        $analysis->close();

        // Phase 3: Signal completion
        title('Analysis: complete');

        notify(
            title: 'Analysis Complete',
            body: count($results) . ' files analyzed. Check your terminal.'
        );
    }
}

Ese es un solo comando Artisan usando title() para la identificación de pestañas, autocomplete() para entrada rápida, task() para el trabajo pesado con progreso en tiempo real, stream() para salida generada por IA, y notify() para la señal de finalización. Hace seis meses, construir este nivel de UX de terminal en PHP habría requerido una librería de terceros o cientos de líneas de código de renderizado personalizado. Ahora son un puñado de llamadas a funciones.

Qué Más Se Publicó Recientemente — Las Versiones de Soporte

Las funcionalidades de v0.3.15 no aparecieron de forma aislada. Las versiones previas sentaron las bases:

v0.3.12 (febrero 2026) agregó soporte para Laravel 13 y corrigió el manejo de validación para el prompt numérico — la entrada numérica introducida en v0.3.11 que permite a los usuarios incrementar y decrementar con las teclas de flecha y aplica restricciones de mín/máx.

v0.3.10 (enero 2026) introdujo el componente Grid para la organización del diseño dentro de interfaces de terminal. Piensa en ello como un flexbox básico para el CLI — posicionando múltiples elementos lado a lado en lugar de apilar todo verticalmente.

v0.3.15 también incluyó información secundaria dinámica en prompts de tipo selección. Ahora puedes pasar un callback que genera texto de detalle secundario para cada opción, mostrado junto a la etiqueta de la opción. Útil para mostrar descripciones, metadatos o indicadores de estado junto a cada elección en una llamada select() o multiselect().

Y una limpieza de PHPStan que mejoró la seguridad de tipos en todo el paquete — el tipo de trabajo invisible que hace que la librería sea más confiable para el autocompletado del IDE y el análisis estático en tus propios proyectos.

Las Primitivas Que Ya Tenías (Pero Que Podrías Estar Subutilizando)

Ya que estamos hablando del kit completo de herramientas de Prompts, aquí hay un inventario rápido de las primitivas existentes que combinan bien con las adiciones de v0.3.15. Las enumero porque la mayoría de los desarrolladores Laravel con los que hablo solo usan select() y confirm() — dejando una UX de terminal significativa sobre la mesa.

Funciones de mensajes informativos:

use function Laravel\Prompts\info;
use function Laravel\Prompts\note;
use function Laravel\Prompts\warning;
use function Laravel\Prompts\error;
use function Laravel\Prompts\alert;

info('Migration complete.');         // Azul, informativo
note('Check the logs for details.'); // Gris, sutil
warning('3 deprecated methods.');    // Amarillo, precautorio
error('Connection refused.');        // Rojo, crítico
alert('Action required!');           // Negrita, demanda atención

Tablas para salida estructurada:

use function Laravel\Prompts\table;

table(
    headers: ['Migration', 'Status', 'Duration'],
    rows: [
        ['2026_03_01_create_users', 'Applied', '0.34s'],
        ['2026_03_02_create_orders', 'Applied', '1.21s'],
        ['2026_03_03_add_indexes', 'Pending', '---'],
    ]
);

Barras de progreso para operaciones iterables:

use function Laravel\Prompts\progress;

$results = progress(
    label: 'Importing records',
    steps: $csvRows,
    callback: function ($row) {
        return $this->importRow($row);
    }
);

Spin para estados de carga simples:

use function Laravel\Prompts\spin;

$result = spin(
    message: 'Fetching remote configuration...',
    callback: fn () => Http::get('https://api.example.com/config')->json()
);

La diferencia entre spin() y task() es el alcance. spin() es para operaciones simples donde solo necesitas "por favor espera" con un spinner y un solo mensaje. task() es para operaciones multifase con salida de log con scroll, actualizaciones de etiqueta y mensajes de estado persistentes. Usa spin() para una llamada API de 3 segundos. Usa task() para un despliegue de 3 minutos.

Cómo Elegir la Primitiva Correcta — Un Marco de Decisión

Después de una semana de reconstruir comandos con estas herramientas, he llegado a un modelo mental para elegir entre ellas:

Usa task() cuando:

  • La operación toma más de 5 segundos
  • Hay múltiples fases de las que el usuario debería saber
  • Tienes salida de log que el usuario podría querer leer
  • Los errores o advertencias necesitan persistir en pantalla
  • Quieres actualizar la etiqueta a medida que la operación avanza

Usa spin() cuando:

  • La operación es un solo paso sin salida de log significativa
  • Termina en menos de 10 segundos
  • Solo necesitas "por favor espera, esto está funcionando"

Usa stream() cuando:

  • Estás renderizando texto generado por IA o en streaming
  • La salida debería aparecer progresivamente, no toda de golpe
  • Quieres el efecto visual de máquina de escribir/aparición gradual

Usa progress() cuando:

  • Estás iterando sobre un número conocido de elementos
  • Cada iteración dura aproximadamente lo mismo
  • Al usuario le beneficia ver "47 de 200 completados"

Usa autocomplete() cuando:

  • El usuario sabe aproximadamente lo que quiere escribir
  • La velocidad importa más que explorar una lista completa
  • Tienes un conjunto pequeño a mediano de opciones predecibles

Usa suggest() cuando:

  • El usuario necesita ver múltiples coincidencias simultáneamente
  • El conjunto de opciones es grande y se beneficia del escaneo visual
  • El descubrimiento es más importante que la velocidad

Usa notify() cuando:

  • El comando dura lo suficiente como para que el usuario cambie de ventana
  • La finalización es un evento que vale la pena interrumpir
  • Estás ejecutando múltiples pestañas de terminal simultáneamente

Usa title() cuando:

  • El comando se ejecuta en una pestaña de terminal persistente
  • Tienes múltiples comandos similares en diferentes pestañas
  • Quieres identificación de un vistazo de lo que cada terminal está haciendo

Si prefieres que alguien construya este tipo de herramientas CLI pulidas y flujos de trabajo de despliegue para tu equipo, acepto consultoría Laravel y proyectos de herramientas Artisan personalizadas. Puedes ver lo que he construido en fiverr.com/s/EgxYmWD.

El Panorama General — El CLI de PHP Está Madurando

Esto es lo que me llama la atención de esta versión. Durante años, la UX de terminal en PHP fue algo secundario. Tenías los helpers de Symfony Console — barras de progreso, tablas, helpers de preguntas — y estaban bien. Funcionales. No hermosos. Simplemente bien.

Laravel Prompts cambió esa trayectoria cuando se lanzó en 2023 con Laravel 10. Pero la versión inicial estaba enfocada en la entrada — text, select, multiselect, confirm. Obtener información del usuario de manera pulida. El lado de la salida — mostrar información al usuario durante operaciones — seguía siendo básico. $this->info() y $this->error() y la ocasional barra de progreso.

v0.3.15 completa el panorama. Entrada y salida ahora son preocupaciones de primera clase. Puedes construir una experiencia CLI que rivaliza con lo que esperarías de una herramienta Node.js construida con Ink o una herramienta Rust construida con Ratatui. Spinners, texto en streaming, etiquetas que se actualizan en vivo, mensajes de estado persistentes, notificaciones nativas, gestión de títulos de terminal — estos son los bloques de construcción que separan un "comando" de una "experiencia."

Y el hecho de que fueron extraídos del Cloud CLI significa que ya sobrevivieron la prueba más difícil: ingenieros reales usándolos todos los días bajo condiciones reales. El spinner necesitaba ser fluido. El scroll del log necesitaba manejar salida rápida sin parpadeos. Las notificaciones necesitaban aparecer de manera confiable en macOS, Linux y WSL. Estas no son funcionalidades teóricas — son funcionalidades endurecidas en producción.

Para el ecosistema Laravel específicamente, creo que esta versión marca un cambio. Los comandos Artisan siempre han sido poderosos en el lado de la lógica. Ahora pueden ser poderosos en el lado de la experiencia también. Y en una era donde los desarrolladores cada vez más eligen herramientas basándose en cómo se sienten al usarlas — no solo en lo que hacen — esa distinción importa más de lo que la mayoría de la gente se da cuenta.

Lo Que Quiero Ver Después

Las primitivas están aquí. La base es sólida. Pero hay vacíos que estoy observando.

Diseños componibles. El componente Grid de v0.3.10 es un comienzo, pero quiero la capacidad de colocar un spinner de task() junto a una table() que se actualice en tiempo real. Elementos lado a lado. Diseños estilo dashboard. El Cloud CLI probablemente tiene algo de esto internamente — espero que más de ello sea extraído.

Atajos de teclado dentro de las tareas. Imagina presionar "v" para alternar el logging verboso, o "s" para saltar el paso actual. Tareas interactivas, no solo tareas de solo visualización. La extensión pcntl ya habilita el manejo de señales — extender eso a la detección de teclas dentro de una tarea en ejecución se siente como el siguiente paso natural.

Soporte de temas. El renderizado actual es hermoso, pero es una sola estética. Diferentes proyectos tienen diferentes entornos de terminal. Una API de temas — incluso una simple que te permita sobrescribir colores y símbolos — haría que Prompts se sienta nativo en la configuración de herramientas de cualquier equipo.

Ninguno de estos son críticas. v0.3.15 es una versión genuinamente fuerte. Pero la trayectoria que establece es posiblemente más emocionante que lo que incluyó. La brecha entre "herramienta CLI de PHP" y "aplicación de terminal pulida" se acaba de reducir considerablemente.

Empieza Con Un Comando

Elige un comando Artisan en tu proyecto — el que tarda más, el que produce más texto, el que tu equipo evita ejecutar porque la experiencia es dolorosa. Reescríbelo con task(). Agrega un notify() al final. Establece el title() al inicio.

Te tomará 30 minutos. El comando hará exactamente lo mismo que hacía antes. Pero se sentirá como una herramienta diferente. Y la próxima vez que alguien en tu equipo lo ejecute, lo notará. Ese es el tipo de mejora que no cuesta nada y cambia todo sobre cómo se percibe tu herramienta.

Las primitivas están ahí. Composer ya las tiene:

composer require laravel/prompts:^0.3.15

O si estás en Laravel 12 o 13, ya vienen incluidas. Solo empieza a usar las funciones.

Un comando. Treinta minutos. Adelante.

Preguntas Frecuentes

¿Funciona task() de Laravel Prompts en Windows?

La función task() funciona en todas las plataformas, pero el spinner animado requiere la extensión PHP PCNTL, que no está disponible en Windows nativo. En Windows, se renderiza una alternativa estática en su lugar. Usar WSL en Windows te da soporte completo de animación ya que ejecuta un kernel Linux real.

¿Cuál es la diferencia entre spin() y task() en Laravel Prompts?

spin() es para operaciones simples de un solo paso donde necesitas un spinner y un mensaje. task() es para operaciones multifase con salida de log con scroll, actualizaciones dinámicas de etiqueta y mensajes persistentes de éxito/advertencia/error. Usa spin() para llamadas API rápidas de menos de 10 segundos; usa task() para despliegues, migraciones y builds de múltiples pasos.

¿Puedo usar stream() de Laravel Prompts para texto generado por IA?

Sí — stream() fue diseñado específicamente para este caso de uso. Llama a $stream->append() con cada fragmento de una respuesta de streaming de una API LLM, y el texto se renderiza con un efecto de aparición progresiva. Llama a $stream->close() cuando el stream termine para finalizar la salida y restaurar el cursor.

¿Qué versión de PHP requiere Laravel Prompts v0.3.15?

Laravel Prompts v0.3.15 requiere PHP 8.1 o superior y la extensión ext-mbstring. Funciona con Symfony Console 6.2, 7.0 y 8.0, y viene incluido con Laravel 12 y Laravel 13.

¿Cómo envío notificaciones de escritorio desde un comando Artisan de Laravel?

Usa la función notify() de Laravel Prompts v0.3.15: notify(title: 'Done', body: 'Your task finished.'). Envía una notificación nativa del sistema operativo en macOS (Centro de Notificaciones), Linux (demonio de notificaciones) y Windows vía WSL. No se requieren paquetes ni configuración adicional.

Let's Work Together

Looking to build AI systems, automate workflows, or scale your tech infrastructure? I'd love to help.

Coffee cup

¿Te gustó este artículo?

Tu apoyo me ayuda a crear más contenido técnico detallado, herramientas de código abierto y recursos gratuitos para la comunidad de desarrolladores.

Temas Relacionados

Engr Mejba Ahmed

Sobre el Autor

Engr Mejba Ahmed

Engr. Mejba Ahmed builds AI-powered applications and secure cloud systems for businesses worldwide. With 10+ years shipping production software in Laravel, Python, and AWS, he's helped companies automate workflows, reduce infrastructure costs, and scale without security headaches. He writes about practical AI integration, cloud architecture, and developer productivity.

Discussion

Comments

0

No comments yet

Be the first to share your thoughts

Leave a Comment

Your email won't be published

10  -  1  =  ?

Seguir Aprendiendo

Artículos Relacionados

Ver Todos

Comments

Leave a Comment

Comments are moderated before appearing.

Learning Resources

Expand Your Knowledge

Accelerate your growth with structured courses, verified certificates, interactive flashcards, and production-ready AI agent skills.

Sample Certificate of Completion

Sample certificate — complete any course to earn yours