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áneamenteautocomplete()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.
- Fiverr (custom builds & integrations): fiverr.com/s/EgxYmWD
- Portfolio: mejba.me
- Ramlit Limited (enterprise solutions): ramlit.com
- ColorPark (design & branding): colorpark.io
- xCyberSecurity (security services): xcybersecurity.io