Skip to main content
📝 Aplicações Laravel

Laravel Prompts v0.3.15: As Primitivas CLI Que Você Precisava

Laravel Prompts v0.3.15 adiciona primitivas de tarefas para comandos CLI. Rastreamento de progresso, etapas sequenciais e UX de terminal mais limpa para comandos Artisan.

25 min

Tempo de leitura

4,928

Palavras

Mar 18, 2026

Publicado

Engr Mejba Ahmed

Escrito por

Engr Mejba Ahmed

Compartilhar Artigo

Laravel Prompts v0.3.15: As Primitivas CLI Que Você Precisava

Laravel Prompts v0.3.15: As Primitivas CLI Que Você Precisava

Eu estava no meio da construção de um comando de deploy para o projeto de um cliente na semana passada quando bati naquele muro que todo desenvolvedor Laravel conhece bem demais. O comando precisava executar seis operações sequenciais — puxar dependências, compilar assets, rodar migrações, limpar caches, pré-aquecer rotas e fazer ping em um health check. Cada etapa levava entre 3 e 45 segundos. E minha experiência de usuário para tudo isso? Um cursor piscando. Talvez uma chamada $this->info() entre as etapas se eu estivesse me sentindo generoso.

O terminal simplesmente ficava ali. Em silêncio. O tipo de silêncio que faz você se perguntar se o processo travou, se deveria apertar Ctrl+C e começar de novo, ou se a migração do banco de dados está genuinamente processando 200.000 linhas e você só precisa esperar.

Então eu vi as notas da versão v0.3.15 serem publicadas em 17 de março de 2026. Cinco novas primitivas. Todas extraídas do CLI do Laravel Cloud — o ferramental interno que o time do Laravel construiu para gerenciar deploys na nuvem. A funcionalidade principal é task(), e ela resolve exatamente o problema que acabei de descrever. Mas o elenco de apoio — stream(), notify(), autocomplete() e title() — preenche lacunas que eu não tinha percebido que vinha contornando há anos.

Liberei minha tarde e refiz aquele comando de deploy. Aqui está tudo o que encontrei.

Por Que Essas Primitivas Existem — E Por Que Chegaram Agora

A história por trás importa porque explica por que essas funcionalidades parecem tão polidas logo de cara.

Quando o time do Laravel construiu o Cloud CLI — a ferramenta de linha de comando que gerencia toda a sua infraestrutura Laravel Cloud — eles precisavam de interações de terminal que fossem muito além de "fazer uma pergunta, obter uma resposta." Deploys na nuvem envolvem processos de longa duração com saída de logs em tempo real. Eles precisam de spinners que atualizem suas labels conforme o contexto muda. Precisam de mensagens de status (sucesso, aviso, erro) que persistam na tela enquanto os logs com scroll fluem abaixo. Precisam de texto em streaming para operações assistidas por IA. Precisam de notificações de desktop quando um deploy de 10 minutos termina enquanto você está em outra janela.

Nada disso existia no Laravel Prompts antes. Então eles construíram internamente. E com a v0.3.15, extraíram essas primitivas de volta para o próprio pacote — testadas em batalha após meses de uso real dentro do Cloud CLI.

Esse padrão de extração é uma das coisas que mais respeito no ecossistema Laravel. Funcionalidades não chegam como APIs teóricas. Elas chegam porque alguém precisou delas em produção, construiu sob pressão, refinou através do uso diário, e então generalizou para todos os outros. A função task() não começou como um documento de especificações. Começou como uma tela de deploy que precisava manter os engenheiros informados durante builds de 5 minutos.

Com mais de 179 milhões de instalações no Packagist e 535 pacotes dependentes, mudanças no Laravel Prompts repercutem por todo o ecossistema PHP. Essa release não é um patch menor — é uma expansão fundamental do que é possível em UI de terminal para aplicações PHP.

Aqui está o que realmente foi incluído.

A Função task() — Processos Longos Finalmente Têm uma UI de Verdade

Esse é o ponto central da v0.3.15, e com razão. A função task() te dá um spinner que atualiza ao vivo, saída de log com scroll, mensagens de status estáveis que persistem na tela, e a capacidade de atualizar a label conforme a tarefa progride. Tudo a partir de uma única chamada de função.

Aqui está a assinatura 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');
    }
);

O que acontece quando isso roda: um spinner anima ao lado de "Deploying application." Conforme seu callback executa, cada chamada $task->log() escreve uma linha em uma área de saída com scroll abaixo do spinner. A área de log faz scroll automaticamente — linhas antigas sobem conforme as novas chegam, mantendo a saída mais recente visível. O spinner continua animando o tempo todo, para que o usuário sempre saiba que o processo está vivo.

A chamada $task->label() é sutil mas poderosa. Ela muda o texto ao lado do spinner sem interromper o scroll do log. Assim você pode mostrar "Pulling dependencies" para a primeira fase, "Compiling assets" para a segunda, "Running migrations" para a terceira — tudo enquanto a saída detalhada do log flui por baixo. Dois níveis de densidade de informação: a label diz em que fase você está, o log diz o que está acontecendo agora.

Mensagens de Status Que Ficam

A parte que me convenceu: mensagens de status estáveis.

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');
    }
);

Quando você chama $task->warning(), essa mensagem é renderizada acima da área de log com scroll como uma linha destacada e persistente. Ela não rola para fora da tela. Fica fixada no topo enquanto o resto do log continua fluindo abaixo. Mesmo comportamento para $task->error(). E $task->succeed() finaliza a tarefa com uma marca de verificação verde e sua mensagem, substituindo o spinner.

Isso resolve um problema que venho remendando há anos: informação importante de status sendo soterrada em saída verbosa. Em um comando de migração, o aviso "3 tabelas serão removidas" não deveria rolar e se perder em uma parede de instruções SQL. Deveria ficar fixo. Agora fica.

O Requisito do PCNTL

Uma coisa para saber: a animação do spinner requer a extensão PHP pcntl. No macOS e na maioria das distribuições Linux, está disponível por padrão. No Windows (sem WSL), a extensão PCNTL não está disponível — você receberá uma versão estática de fallback. A tarefa ainda funciona, o log ainda gera saída, mas o spinner não vai animar.

Verifique se você tem:

php -m | grep pcntl

Se você está construindo comandos Artisan que precisam rodar multiplataforma, projete sua saída para ser útil mesmo sem a animação. A função task() lida com isso graciosamente — você não precisa escrever código condicional.

Meu Comando de Deploy, Reconstruído

Aqui está como meu comando de deploy ficou agora versus antes. A diferença na experiência do usuário é dramática.

Antes (a era das trevas):

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. Mas o usuário não vê nada por 30 segundos seguidos, depois uma rajada de texto estático. Nenhuma indicação de progresso durante cada etapa. Nenhuma distinção entre "está tudo bem" e "algo deu errado mas continuamos."

Depois (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.'
    );
}

O terminal agora mostra um indicador giratório durante cada fase, a label atualiza conforme o comando progride pelas etapas, cada linha de saída real do git, Composer e npm flui no log com scroll, erros aparecem imediatamente como mensagens de status fixadas, e quando termina, uma notificação nativa de desktop aparece. Essa última parte — a notificação — nos leva à próxima primitiva.

notify() — Notificações Nativas de Desktop a Partir do PHP

Essa me surpreendeu. Não porque notificações de desktop sejam um conceito novo, mas porque eu nunca esperava isso de uma ferramenta CLI em PHP.

use function Laravel\Prompts\notify;

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

É isso. Uma notificação nativa do sistema operacional aparece — do mesmo tipo que você recebe do Slack, VS Code ou seu cliente de e-mail. No macOS, usa o centro de notificações do sistema. No Linux, funciona através do daemon de notificações padrão. No Windows com WSL, faz a ponte com as notificações do Windows.

O caso de uso que imediatamente fez sentido para mim: comandos Artisan de longa duração que eu disparo e esqueço. Inicio um seed de banco de dados que leva 8 minutos, mudo para meu editor, começo a trabalhar em outra coisa, e esqueço completamente do terminal. Vinte minutos depois me pergunto "aquilo terminou?" e tenho que ir verificar.

Agora adiciono uma linha no final do comando. A notificação me encontra onde quer que eu esteja.

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

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

Uma coisa pequena. Mas coisas pequenas que eliminam carga cognitiva se acumulam em uma experiência de desenvolvimento genuinamente melhor.

stream() — Texto Que Se Digita Sozinho no Terminal

Se task() é o cavalo de batalha desta versão, stream() é a peça de exibição. Ele exibe texto que flui no terminal caractere por caractere (ou chunk por chunk), com um efeito gradual de aparecimento.

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();

O método append() adiciona texto com um efeito visual de aparecimento progressivo — os caracteres se materializam gradualmente em vez de aparecer todos de uma vez. Isso pode soar como um truque até você considerar o caso de uso principal: exibir conteúdo gerado por IA no terminal.

Se você está construindo comandos Artisan que chamam OpenAI, Anthropic, ou qualquer outra API de LLM com respostas em streaming, stream() te dá o mesmo efeito de máquina de escrever que você vê na interface do ChatGPT — mas no seu terminal. O texto chega conforme o modelo o gera, e stream() o renderiza com aquela revelação progressiva satisfatória.

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();

O método close() finaliza a saída, restaura o cursor e sinaliza que o streaming está completo. Sem ele, o terminal ficaria em um estado indeterminado.

Já consigo ver isso se tornando padrão em comandos Artisan potencializados por IA — o tipo de ferramenta que está rapidamente se tornando normal em aplicações Laravel desde que o ecossistema abraçou integrações de IA ao longo de 2025 e em 2026. Ter uma primitiva de renderização de primeira classe para texto em streaming é exatamente o suporte fundamental que o pacote precisava.

autocomplete() — Texto Fantasma no Terminal

A função autocomplete() adiciona autocompletar inline a entradas de texto, mostrando sugestões como texto fantasma que o usuário pode aceitar com Tab ou a tecla de seta para a direita.

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()
);

Digite "la" e "Laravel" aparece como texto fantasma esmaecido após seu cursor. Pressione Tab para aceitar. Se continuar digitando "lum," o texto fantasma muda para "Lumen." O callback de opções recebe o valor de entrada atual e retorna sugestões correspondentes em tempo real.

A diferença entre autocomplete() e a função existente suggest() é o modelo de interação. suggest() mostra uma lista suspensa de opções correspondentes abaixo da entrada. autocomplete() mostra texto fantasma inline — o mesmo padrão que você conhece do GitHub Copilot, sua IDE, ou barras de endereço de navegadores modernos. É mais rápido para usuários experientes que sabem o que querem e só precisam que o sistema complete seu pensamento.

Quando usar cada um?

  • suggest() funciona quando o usuário está navegando opções e precisa ver múltiplas correspondências simultaneamente
  • autocomplete() funciona quando o usuário sabe mais ou menos a resposta e quer velocidade — menos teclas digitadas, fluxo mais rápido

Para comandos que desenvolvedores experientes executam diariamente — selecionar ambientes, escolher branches, especificar nomes de models — autocomplete() vai parecer notavelmente mais ágil que suggest().

title() — Defina o Título da Janela do Terminal

Esse é enganosamente simples:

use function Laravel\Prompts\title;

title('Application Installer');

Ele muda o título da janela ou aba do terminal. É isso. O texto na barra de título do seu terminal ou na label da aba atualiza para qualquer string que você passe.

Por que isso importa? Porque qualquer pessoa que rode mais de três abas de terminal simultaneamente conhece a dor de procurar pela certa. Se seu comando Artisan define o título como "Deploying: staging" ou "Queue Worker: emails" ou "Migrating: production," encontrar a aba certa se torna instantâneo.

Combine com notify() para comandos de longa duração:

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')
);

A aba do terminal te diz o estado num relance. A notificação te traz de volta quando você está em outro lugar. Duas primitivas, e seu comando de deploy respeita sua atenção em vez de exigi-la.

Juntando Tudo — Um Comando do Mundo Real

Primitivas individuais são interessantes. Combinadas, são transformadoras. Aqui está um comando Artisan completo que usa cada nova funcionalidade da v0.3.15 — o tipo de comando que você realmente poderia construir para um fluxo de trabalho em produção:

<?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.'
        );
    }
}

Esse é um único comando Artisan usando title() para identificação de abas, autocomplete() para entrada rápida, task() para o trabalho pesado com progresso em tempo real, stream() para saída gerada por IA, e notify() para o sinal de conclusão. Seis meses atrás, construir esse nível de UX de terminal em PHP teria exigido uma biblioteca de terceiros ou centenas de linhas de código de renderização customizado. Agora são um punhado de chamadas de funções.

O Que Mais Foi Lançado Recentemente — As Releases de Suporte

As funcionalidades da v0.3.15 não apareceram isoladamente. As releases anteriores prepararam o terreno:

v0.3.12 (fevereiro 2026) adicionou suporte ao Laravel 13 e corrigiu o tratamento de validação para o prompt numérico — a entrada numérica introduzida na v0.3.11 que permite aos usuários incrementar e decrementar com as teclas de seta e impõe restrições de mín/máx.

v0.3.10 (janeiro 2026) introduziu o componente Grid para organização de layout dentro de interfaces de terminal. Pense nele como um flexbox básico para o CLI — posicionando múltiplos elementos lado a lado em vez de empilhar tudo verticalmente.

v0.3.15 também incluiu informação secundária dinâmica em prompts do tipo seleção. Agora você pode passar um callback que gera texto de detalhe secundário para cada opção, exibido ao lado da label da opção. Útil para mostrar descrições, metadados ou indicadores de status ao lado de cada escolha em uma chamada select() ou multiselect().

E uma limpeza de PHPStan que melhorou a segurança de tipos em todo o pacote — o tipo de trabalho invisível que torna a biblioteca mais confiável para autocompletar da IDE e análise estática nos seus próprios projetos.

As Primitivas Que Você Já Tinha (Mas Pode Estar Subutilizando)

Já que estamos falando do kit completo de ferramentas do Prompts, aqui vai um inventário rápido das primitivas existentes que combinam bem com as adições da v0.3.15. Estou listando porque a maioria dos desenvolvedores Laravel com quem converso só usa select() e confirm() — deixando uma UX de terminal significativa na mesa.

Funções de mensagens informativas:

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.'); // Cinza, sutil
warning('3 deprecated methods.');    // Amarelo, cauteloso
error('Connection refused.');        // Vermelho, crítico
alert('Action required!');           // Negrito, exige atenção

Tabelas para saída estruturada:

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 progresso para operações iteráveis:

use function Laravel\Prompts\progress;

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

Spin para estados de carregamento simples:

use function Laravel\Prompts\spin;

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

A diferença entre spin() e task() é o escopo. spin() é para operações simples onde você só precisa de "por favor aguarde" com um spinner e uma única mensagem. task() é para operações multifase com saída de log com scroll, atualizações de label e mensagens de status persistentes. Use spin() para uma chamada de API de 3 segundos. Use task() para um deploy de 3 minutos.

Como Escolher a Primitiva Certa — Um Framework de Decisão

Depois de uma semana reconstruindo comandos com essas ferramentas, cheguei a um modelo mental para escolher entre elas:

Use task() quando:

  • A operação leva mais de 5 segundos
  • Há múltiplas fases que o usuário deveria conhecer
  • Você tem saída de log que o usuário pode querer ler
  • Erros ou avisos precisam persistir na tela
  • Você quer atualizar a label conforme a operação progride

Use spin() quando:

  • A operação é uma única etapa sem saída de log significativa
  • Termina em menos de 10 segundos
  • Você só precisa de "por favor aguarde, está funcionando"

Use stream() quando:

  • Você está renderizando texto gerado por IA ou em streaming
  • A saída deveria aparecer progressivamente, não toda de uma vez
  • Você quer o efeito visual de máquina de escrever/aparecimento gradual

Use progress() quando:

  • Você está iterando sobre um número conhecido de itens
  • Cada iteração tem aproximadamente a mesma duração
  • O usuário se beneficia de ver "47 de 200 concluídos"

Use autocomplete() quando:

  • O usuário sabe mais ou menos o que quer digitar
  • Velocidade importa mais que navegar por uma lista completa
  • Você tem um conjunto pequeno a médio de opções previsíveis

Use suggest() quando:

  • O usuário precisa ver múltiplas correspondências simultaneamente
  • O conjunto de opções é grande e se beneficia de escaneamento visual
  • Descoberta é mais importante que velocidade

Use notify() quando:

  • O comando roda por tempo suficiente para o usuário mudar de janela
  • A conclusão é um evento que vale a pena interromper
  • Você está rodando múltiplas abas de terminal simultaneamente

Use title() quando:

  • O comando roda em uma aba de terminal persistente
  • Você tem múltiplos comandos similares em abas diferentes
  • Você quer identificação num relance do que cada terminal está fazendo

Se você prefere que alguém construa esse tipo de ferramentas CLI polidas e fluxos de trabalho de deploy para sua equipe, aceito consultoria Laravel e projetos de ferramentas Artisan customizadas. Você pode ver o que já construí em fiverr.com/s/EgxYmWD.

O Panorama Geral — O CLI do PHP Está Amadurecendo

Eis o que me impressiona nesta release. Por anos, a UX de terminal em PHP era uma preocupação secundária. Você tinha os helpers do Symfony Console — barras de progresso, tabelas, helpers de perguntas — e eram OK. Funcionais. Não bonitos. Apenas OK.

Laravel Prompts mudou essa trajetória quando foi lançado em 2023 com o Laravel 10. Mas a release inicial era focada em entrada — text, select, multiselect, confirm. Obter informação do usuário de forma polida. O lado da saída — mostrar informação para o usuário durante operações — ainda era básico. $this->info() e $this->error() e a ocasional barra de progresso.

v0.3.15 completa o quadro. Entrada e saída agora são preocupações de primeira classe. Você pode construir uma experiência CLI que rivaliza com o que esperaria de uma ferramenta Node.js construída com Ink ou uma ferramenta Rust construída com Ratatui. Spinners, texto em streaming, labels que atualizam ao vivo, mensagens de status persistentes, notificações nativas, gerenciamento de títulos de terminal — esses são os blocos de construção que separam um "comando" de uma "experiência."

E o fato de terem sido extraídos do Cloud CLI significa que já sobreviveram ao teste mais difícil: engenheiros reais usando-os todos os dias sob condições reais. O spinner precisava ser suave. O scroll do log precisava lidar com saída rápida sem flicker. As notificações precisavam realmente aparecer de forma confiável no macOS, Linux e WSL. Essas não são funcionalidades teóricas — são funcionalidades endurecidas em produção.

Para o ecossistema Laravel especificamente, acredito que esta release marca uma mudança. Comandos Artisan sempre foram poderosos no lado da lógica. Agora podem ser poderosos no lado da experiência também. E em uma era onde desenvolvedores cada vez mais escolhem ferramentas baseando-se em como elas se sentem ao usar — não apenas no que fazem — essa distinção importa mais do que a maioria das pessoas percebe.

O Que Quero Ver a Seguir

As primitivas estão aqui. A base é sólida. Mas há lacunas que estou observando.

Layouts componíveis. O componente Grid da v0.3.10 é um começo, mas quero a capacidade de colocar um spinner de task() ao lado de uma table() que atualiza em tempo real. Elementos lado a lado. Layouts estilo dashboard. O Cloud CLI provavelmente tem algo disso internamente — espero que mais disso seja extraído.

Atalhos de teclado dentro de tarefas. Imagine pressionar "v" para alternar logging verboso, ou "s" para pular a etapa atual. Tarefas interativas, não apenas tarefas somente de exibição. A extensão pcntl já habilita o tratamento de sinais — estender isso para detecção de teclas dentro de uma tarefa em execução parece o próximo passo natural.

Suporte a temas. A renderização atual é bonita, mas é uma única estética. Projetos diferentes têm ambientes de terminal diferentes. Uma API de temas — mesmo uma simples que permita sobrescrever cores e símbolos — faria o Prompts parecer nativo na configuração de ferramentas de qualquer equipe.

Nenhum desses são críticas. v0.3.15 é uma release genuinamente forte. Mas a trajetória que ela estabelece é possivelmente mais empolgante do que o que incluiu. A distância entre "ferramenta CLI de PHP" e "aplicação de terminal polida" ficou muito menor.

Comece Com Um Comando

Escolha um comando Artisan no seu projeto — o que leva mais tempo, o que gera mais texto, o que sua equipe evita rodar porque a experiência é dolorosa. Reescreva-o com task(). Adicione um notify() no final. Defina o title() no início.

Vai levar 30 minutos. O comando vai fazer exatamente o que fazia antes. Mas vai parecer uma ferramenta diferente. E na próxima vez que alguém da sua equipe rodá-lo, vai notar. Esse é o tipo de melhoria que não custa nada e muda tudo sobre como suas ferramentas são percebidas.

As primitivas estão lá. O Composer já as tem:

composer require laravel/prompts:^0.3.15

Ou se você está no Laravel 12 ou 13, já vêm incluídas. É só começar a usar as funções.

Um comando. Trinta minutos. Vai.

Perguntas Frequentes

O task() do Laravel Prompts funciona no Windows?

A função task() funciona em todas as plataformas, mas o spinner animado requer a extensão PHP PCNTL, que não está disponível no Windows nativo. No Windows, uma alternativa estática é renderizada. Usar WSL no Windows te dá suporte completo à animação, já que roda um kernel Linux real.

Qual é a diferença entre spin() e task() no Laravel Prompts?

spin() é para operações simples de uma única etapa onde você precisa de um spinner e uma mensagem. task() é para operações multifase com saída de log com scroll, atualizações dinâmicas de label e mensagens persistentes de sucesso/aviso/erro. Use spin() para chamadas de API rápidas de menos de 10 segundos; use task() para deploys, migrações e builds de múltiplas etapas.

Posso usar o stream() do Laravel Prompts para texto gerado por IA?

Sim — stream() foi projetado especificamente para esse caso de uso. Chame $stream->append() com cada chunk de uma resposta de streaming de uma API LLM, e o texto é renderizado com um efeito de aparecimento progressivo. Chame $stream->close() quando o stream terminar para finalizar a saída e restaurar o cursor.

Qual versão do PHP o Laravel Prompts v0.3.15 requer?

Laravel Prompts v0.3.15 requer PHP 8.1 ou superior e a extensão ext-mbstring. Funciona com Symfony Console 6.2, 7.0 e 8.0, e vem incluído com Laravel 12 e Laravel 13.

Como envio notificações de desktop a partir de um comando Artisan do Laravel?

Use a função notify() do Laravel Prompts v0.3.15: notify(title: 'Done', body: 'Your task finished.'). Ela envia uma notificação nativa do SO no macOS (Central de Notificações), Linux (daemon de notificações) e Windows via WSL. Nenhum pacote ou configuração adicional necessário.

Let's Work Together

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

Coffee cup

Gostou deste artigo?

Seu apoio me ajuda a criar mais conteúdo técnico aprofundado, ferramentas open-source e recursos gratuitos para a comunidade de desenvolvedores.

Tópicos Relacionados

Engr Mejba Ahmed

Sobre o 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

20  -  15  =  ?

Continue Aprendendo

Artigos 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

Engr Mejba Ahmed

Engr Mejba Ahmed

Claude Code Expert · Online

👋

Hey there!

Quick Actions

WhatsApp Instant reply

Chat on WhatsApp

+880 1723 741224 · Instant reply

Popular Questions

Engr Mejba Ahmed is connected
Engr Mejba Ahmed is typing...
Engr Mejba Ahmed avatar

✉ Want me to follow up? Drop your email

Engr Mejba Ahmed avatar

📞 Connect Directly

Choose how you'd like to reach me

WhatsApp

+880 1723 741224

Email

[email protected]

✓ Details sent! I'll get back to you shortly.

Powered by OpenAI

335+

Blog Posts

25

AI Courses

63

Projects

Services & Expertise

Pricing & Process

Learning & Resources

Connect & Support