Laravel Prompts v0.3.15 : Les Primitives CLI Dont Vous Aviez Besoin
J'étais en plein milieu de la construction d'une commande de déploiement pour le projet d'un client la semaine dernière quand j'ai heurté le mur que tout développeur Laravel connaît trop bien. La commande devait exécuter six opérations séquentielles — récupérer les dépendances, compiler les assets, exécuter les migrations, vider les caches, préchauffer les routes et faire un ping au health check. Chaque étape prenait entre 3 et 45 secondes. Et mon expérience utilisateur pour tout ça ? Un curseur clignotant. Peut-être un appel $this->info() entre les étapes si j'étais d'humeur généreuse.
Le terminal restait là. Silencieux. Le genre de silence qui vous fait vous demander si le processus s'est bloqué, si vous devriez faire Ctrl+C et recommencer, ou si la migration de la base de données est vraiment en train de traiter 200 000 lignes et qu'il faut juste attendre.
Puis j'ai vu les notes de version v0.3.15 tomber le 17 mars 2026. Cinq nouvelles primitives. Toutes extraites du CLI Laravel Cloud — l'outillage interne que l'équipe Laravel a construit pour gérer les déploiements cloud. La fonctionnalité phare est task(), et elle résout exactement le problème que je viens de décrire. Mais le casting secondaire — stream(), notify(), autocomplete() et title() — comble des lacunes que je n'avais pas réalisé que je contournais depuis des années.
J'ai libéré mon après-midi et j'ai refondu cette commande de déploiement. Voici tout ce que j'ai trouvé.
Pourquoi Ces Primitives Existent — Et Pourquoi Elles Arrivent Maintenant
L'histoire compte ici parce qu'elle explique pourquoi ces fonctionnalités semblent si abouties dès le départ.
Quand l'équipe Laravel a construit le Cloud CLI — l'outil en ligne de commande qui gère toute votre infrastructure Laravel Cloud — ils avaient besoin d'interactions terminal qui allaient bien au-delà de « poser une question, obtenir une réponse ». Les déploiements cloud impliquent des processus de longue durée avec une sortie de logs en temps réel. Ils ont besoin de spinners qui mettent à jour leurs labels à mesure que le contexte change. Ils ont besoin de messages de statut (succès, avertissement, erreur) qui persistent à l'écran pendant que les logs défilent en dessous. Ils ont besoin de texte en streaming pour les opérations assistées par IA. Ils ont besoin de notifications de bureau quand un déploiement de 10 minutes se termine pendant que vous êtes dans une autre fenêtre.
Rien de tout cela n'existait dans Laravel Prompts auparavant. Alors ils l'ont construit en interne. Et avec la v0.3.15, ils ont extrait ces primitives vers le package lui-même — éprouvées au combat après des mois d'utilisation réelle au sein du Cloud CLI.
Ce pattern d'extraction est l'une des choses que je respecte le plus dans l'écosystème Laravel. Les fonctionnalités n'arrivent pas comme des APIs théoriques. Elles arrivent parce que quelqu'un en a eu besoin en production, les a construites sous pression, les a affinées par l'usage quotidien, puis les a généralisées pour tout le monde. La fonction task() n'a pas commencé comme un document de spécifications. Elle a commencé comme un écran de déploiement qui devait tenir les ingénieurs informés pendant des builds de 5 minutes.
Avec plus de 179 millions d'installations sur Packagist et 535 packages dépendants, les changements dans Laravel Prompts se propagent dans tout l'écosystème PHP. Cette version n'est pas un correctif mineur — c'est une expansion fondamentale de ce qui est possible en matière d'interface terminal pour les applications PHP.
Voici ce qui a réellement été livré.
La Fonction task() — Les Processus Longs Ont Enfin une Vraie UI
C'est la pièce maîtresse de la v0.3.15, et pour de bonnes raisons. La fonction task() vous donne un spinner qui se met à jour en direct, une sortie de log avec défilement, des messages de statut stables qui persistent à l'écran, et la possibilité de mettre à jour le label à mesure que la tâche progresse. Le tout à partir d'un seul appel de fonction.
Voici la signature de base :
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');
}
);
Voici ce qui se passe à l'exécution : un spinner s'anime à côté de « Deploying application. » À mesure que votre callback s'exécute, chaque appel $task->log() écrit une ligne dans une zone de sortie défilante sous le spinner. La zone de log défile automatiquement — les anciennes lignes remontent à mesure que les nouvelles arrivent, gardant la sortie la plus récente visible. Le spinner continue de s'animer pendant tout ce temps, pour que l'utilisateur sache toujours que le processus est en vie.
L'appel $task->label() est subtil mais puissant. Il change le texte à côté du spinner sans interrompre le défilement du log. Ainsi vous pouvez afficher « Pulling dependencies » pour la première phase, « Compiling assets » pour la deuxième, « Running migrations » pour la troisième — le tout pendant que la sortie détaillée du log défile en dessous. Deux niveaux de densité d'information : le label vous dit dans quelle phase vous êtes, le log vous dit ce qui se passe maintenant.
Des Messages de Statut Qui Restent
La partie qui m'a convaincu : les messages de statut stables.
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');
}
);
Quand vous appelez $task->warning(), ce message se rend au-dessus de la zone de log défilante sous forme de ligne surlignée et persistante. Il ne défile pas hors de l'écran. Il reste épinglé en haut pendant que le reste du log continue de couler en dessous. Même comportement pour $task->error(). Et $task->succeed() finalise la tâche avec une coche verte et votre message, remplaçant le spinner.
Cela résout un problème que je bricole depuis des années : des informations de statut importantes qui se perdent dans une sortie verbeuse. Dans une commande de migration, l'avertissement « 3 tables seront supprimées » ne devrait pas défiler et disparaître dans un mur d'instructions SQL. Il devrait rester. Maintenant c'est le cas.
L'Exigence PCNTL
Une chose à savoir : l'animation du spinner nécessite l'extension PHP pcntl. Sur macOS et la plupart des distributions Linux, elle est disponible par défaut. Sur Windows (sans WSL), l'extension PCNTL n'est pas disponible — vous obtiendrez une version statique de repli à la place. La tâche fonctionne toujours, le log continue de s'afficher, mais le spinner ne s'animera pas.
Vérifiez si vous l'avez :
php -m | grep pcntl
Si vous construisez des commandes Artisan qui doivent fonctionner sur plusieurs plateformes, concevez votre sortie pour qu'elle soit utile même sans l'animation. La fonction task() gère cela avec élégance — vous n'avez pas besoin d'écrire du code conditionnel.
Ma Commande de Déploiement, Reconstruite
Voici à quoi ressemble ma commande de déploiement maintenant par rapport à avant. La différence en expérience utilisateur est spectaculaire.
Avant (l'âge sombre) :
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!');
}
Fonctionnel ? Bien sûr. Mais l'utilisateur ne voit rien pendant 30 secondes d'affilée, puis une rafale de texte statique. Aucune indication de progression pendant chaque étape. Aucune distinction entre « tout va bien » et « quelque chose a échoué mais on a continué. »
Aprè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.'
);
}
Le terminal affiche maintenant un indicateur rotatif pendant chaque phase, le label se met à jour à mesure que la commande progresse à travers les étapes, chaque ligne de sortie réelle de git, Composer et npm défile dans le log, les erreurs apparaissent immédiatement comme des messages de statut épinglés, et quand c'est fini, une notification native de bureau s'affiche. Cette dernière partie — la notification — nous amène à la prochaine primitive.
notify() — Des Notifications de Bureau Natives Depuis PHP
Celle-ci m'a surpris. Pas parce que les notifications de bureau sont un concept nouveau, mais parce que je ne les attendais jamais d'un outil CLI en PHP.
use function Laravel\Prompts\notify;
notify(
title: 'Build Complete',
body: 'Your application has been compiled and deployed.'
);
C'est tout. Une notification native du système d'exploitation apparaît — du même type que celles que vous recevez de Slack, VS Code ou votre client email. Sur macOS, elle utilise le centre de notifications du système. Sur Linux, elle passe par le daemon de notifications standard. Sur Windows avec WSL, elle fait le pont avec les notifications Windows.
Le cas d'usage qui m'a immédiatement parlé : les commandes Artisan de longue durée que je lance et que j'oublie. Je démarre un seed de base de données qui prend 8 minutes, je bascule sur mon éditeur, je commence à travailler sur autre chose, et j'oublie complètement le terminal. Vingt minutes plus tard je me demande « est-ce que c'est fini ? » et je dois aller vérifier.
Maintenant j'ajoute une ligne à la fin de la commande. La notification me retrouve où que je sois.
public function handle()
{
// ... 8 minutes of seeding ...
notify(
title: 'Database Seeded',
body: sprintf('%d records created in %d seconds.', $count, $elapsed)
);
}
Une petite chose. Mais les petites choses qui éliminent la charge cognitive s'accumulent pour créer une expérience de développement véritablement meilleure.
stream() — Du Texte Qui Se Tape Tout Seul dans le Terminal
Si task() est le cheval de bataille de cette version, stream() est la pièce d'apparat. Il affiche du texte qui coule dans le terminal caractère par caractère (ou chunk par chunk), avec un effet d'apparition graduel.
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();
La méthode append() ajoute du texte avec un effet visuel d'apparition progressive — les caractères se matérialisent progressivement plutôt que d'apparaître tous d'un coup. Cela peut sembler gadget jusqu'à ce que vous considériez le cas d'usage principal : afficher du contenu généré par IA dans le terminal.
Si vous construisez des commandes Artisan qui appellent OpenAI, Anthropic, ou toute autre API LLM avec des réponses en streaming, stream() vous donne le même effet machine à écrire que vous voyez dans l'interface de ChatGPT — mais dans votre terminal. Le texte arrive au fur et à mesure que le modèle le génère, et stream() le rend avec cette révélation progressive satisfaisante.
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();
La méthode close() finalise la sortie, restaure le curseur et signale que le streaming est terminé. Sans elle, le terminal resterait dans un état indéterminé.
Je vois déjà cela devenir standard dans les commandes Artisan alimentées par l'IA — le genre d'outillage qui devient rapidement normal dans les applications Laravel depuis que l'écosystème a adopté les intégrations IA tout au long de 2025 et jusqu'en 2026. Avoir une primitive de rendu de première classe pour le texte en streaming est exactement le support fondamental dont le package avait besoin.
autocomplete() — Du Texte Fantôme dans le Terminal
La fonction autocomplete() ajoute l'auto-complétion inline aux champs de saisie, affichant des suggestions sous forme de texte fantôme que l'utilisateur peut accepter avec Tab ou la touche flèche droite.
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()
);
Tapez « la » et « Laravel » apparaît comme texte fantôme estompé après votre curseur. Appuyez sur Tab pour l'accepter. Si vous continuez à taper « lum », le texte fantôme bascule sur « Lumen ». Le callback d'options reçoit la valeur de saisie actuelle et retourne les suggestions correspondantes en temps réel.
La différence entre autocomplete() et la fonction existante suggest() est le modèle d'interaction. suggest() affiche une liste déroulante d'options correspondantes sous la saisie. autocomplete() affiche du texte fantôme inline — le même pattern que vous connaissez de GitHub Copilot, votre IDE, ou les barres d'adresse des navigateurs modernes. C'est plus rapide pour les utilisateurs expérimentés qui savent ce qu'ils veulent et ont juste besoin que le système finisse leur pensée.
Quand utiliser chacun ?
suggest()fonctionne quand l'utilisateur parcourt les options et a besoin de voir plusieurs correspondances simultanémentautocomplete()fonctionne quand l'utilisateur connaît approximativement la réponse et veut de la vitesse — moins de frappes, flux plus rapide
Pour les commandes que les développeurs expérimentés exécutent quotidiennement — sélectionner des environnements, choisir des branches, spécifier des noms de models — autocomplete() sera notablement plus vif que suggest().
title() — Définissez le Titre de la Fenêtre du Terminal
Celui-ci est d'une simplicité trompeuse :
use function Laravel\Prompts\title;
title('Application Installer');
Il change le titre de la fenêtre ou de l'onglet du terminal. C'est tout. Le texte dans la barre de titre de votre terminal ou le label de l'onglet se met à jour avec la chaîne que vous passez.
Pourquoi est-ce important ? Parce que quiconque lance plus de trois onglets de terminal simultanément connaît la douleur de chercher le bon. Si votre commande Artisan définit le titre sur « Deploying: staging » ou « Queue Worker: emails » ou « Migrating: production », trouver le bon onglet devient instantané.
Combinez-le avec notify() pour les commandes de longue durée :
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')
);
L'onglet du terminal vous indique l'état d'un coup d'oeil. La notification vous ramène quand vous êtes ailleurs. Deux primitives, et votre commande de déploiement respecte votre attention au lieu de l'exiger.
Tout Assembler — Une Commande du Monde Réel
Les primitives individuelles sont intéressantes. Combinées, elles sont transformatrices. Voici une commande Artisan complète qui utilise chaque nouvelle fonctionnalité de la v0.3.15 — le type de commande que vous pourriez réellement construire pour un workflow de production :
<?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.'
);
}
}
C'est une seule commande Artisan utilisant title() pour l'identification des onglets, autocomplete() pour une saisie rapide, task() pour le gros du travail avec un suivi de progression en temps réel, stream() pour la sortie générée par IA, et notify() pour le signal de fin. Il y a six mois, construire ce niveau d'UX terminal en PHP aurait nécessité une bibliothèque tierce ou des centaines de lignes de code de rendu personnalisé. Maintenant c'est une poignée d'appels de fonctions.
Ce Qui a Été Livré Récemment — Les Versions de Support
Les fonctionnalités de la v0.3.15 ne sont pas apparues de manière isolée. Les versions précédentes ont posé les bases :
v0.3.12 (février 2026) a ajouté le support de Laravel 13 et corrigé la gestion de la validation pour le prompt numérique — la saisie numérique introduite dans la v0.3.11 qui permet aux utilisateurs d'incrémenter et décrémenter avec les touches fléchées et applique des contraintes min/max.
v0.3.10 (janvier 2026) a introduit le composant Grid pour l'organisation de la mise en page au sein des interfaces terminal. Pensez-y comme un flexbox basique pour le CLI — positionnant plusieurs éléments côte à côte plutôt que de tout empiler verticalement.
v0.3.15 a aussi livré des informations secondaires dynamiques sur les prompts de type sélection. Vous pouvez maintenant passer un callback qui génère du texte de détail secondaire pour chaque option, affiché à côté du label de l'option. Utile pour afficher des descriptions, des métadonnées ou des indicateurs de statut à côté de chaque choix dans un appel select() ou multiselect().
Et un nettoyage PHPStan qui a amélioré la sécurité des types dans tout le package — le genre de travail invisible qui rend la bibliothèque plus fiable pour l'auto-complétion de l'IDE et l'analyse statique dans vos propres projets.
Les Primitives Que Vous Aviez Déjà (Mais Que Vous Sous-Utilisez Peut-Être)
Puisque nous parlons de la boîte à outils complète de Prompts, voici un inventaire rapide des primitives existantes qui se combinent bien avec les ajouts de la v0.3.15. Je les liste parce que la plupart des développeurs Laravel à qui je parle n'utilisent que select() et confirm() — laissant une UX terminal significative de côté.
Fonctions de messages informatifs :
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.'); // Bleu, informatif
note('Check the logs for details.'); // Gris, subtil
warning('3 deprecated methods.'); // Jaune, prudent
error('Connection refused.'); // Rouge, critique
alert('Action required!'); // Gras, demande l'attention
Tables pour une sortie structurée :
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', '---'],
]
);
Barres de progression pour les opérations itérables :
use function Laravel\Prompts\progress;
$results = progress(
label: 'Importing records',
steps: $csvRows,
callback: function ($row) {
return $this->importRow($row);
}
);
Spin pour les états de chargement simples :
use function Laravel\Prompts\spin;
$result = spin(
message: 'Fetching remote configuration...',
callback: fn () => Http::get('https://api.example.com/config')->json()
);
La différence entre spin() et task() est la portée. spin() est pour les opérations simples où vous avez juste besoin de « veuillez patienter » avec un spinner et un seul message. task() est pour les opérations multi-phases avec une sortie de log défilante, des mises à jour de label et des messages de statut persistants. Utilisez spin() pour un appel API de 3 secondes. Utilisez task() pour un déploiement de 3 minutes.
Comment Choisir la Bonne Primitive — Un Cadre de Décision
Après une semaine à reconstruire des commandes avec ces outils, j'ai abouti à un modèle mental pour choisir entre eux :
Utilisez task() quand :
- L'opération prend plus de 5 secondes
- Il y a plusieurs phases dont l'utilisateur devrait être informé
- Vous avez une sortie de log que l'utilisateur pourrait vouloir lire
- Les erreurs ou avertissements doivent persister à l'écran
- Vous voulez mettre à jour le label à mesure que l'opération progresse
Utilisez spin() quand :
- L'opération est une seule étape sans sortie de log significative
- Elle se termine en moins de 10 secondes
- Vous avez juste besoin de « veuillez patienter, ça fonctionne »
Utilisez stream() quand :
- Vous rendez du texte généré par IA ou en streaming
- La sortie devrait apparaître progressivement, pas d'un seul coup
- Vous voulez l'effet visuel de machine à écrire/apparition progressive
Utilisez progress() quand :
- Vous itérez sur un nombre connu d'éléments
- Chaque itération dure approximativement la même durée
- L'utilisateur bénéficie de voir « 47 sur 200 terminés »
Utilisez autocomplete() quand :
- L'utilisateur sait à peu près ce qu'il veut taper
- La vitesse compte plus que le parcours d'une liste complète
- Vous avez un ensemble petit à moyen d'options prévisibles
Utilisez suggest() quand :
- L'utilisateur a besoin de voir plusieurs correspondances simultanément
- L'ensemble d'options est grand et bénéficie d'un balayage visuel
- La découverte est plus importante que la vitesse
Utilisez notify() quand :
- La commande dure assez longtemps pour que l'utilisateur change de fenêtre
- La complétion est un événement qui mérite d'interrompre
- Vous exécutez plusieurs onglets de terminal simultanément
Utilisez title() quand :
- La commande s'exécute dans un onglet de terminal persistant
- Vous avez plusieurs commandes similaires dans différents onglets
- Vous voulez une identification instantanée de ce que fait chaque terminal
Si vous préférez que quelqu'un construise ce genre d'outils CLI soignés et de workflows de déploiement pour votre équipe, j'accepte des missions de consulting Laravel et de création d'outils Artisan personnalisés. Vous pouvez voir ce que j'ai construit sur fiverr.com/s/EgxYmWD.
La Vue d'Ensemble — Le CLI PHP Grandit
Voici ce qui me frappe dans cette version. Pendant des années, l'UX terminal en PHP était un détail secondaire. Vous aviez les helpers de Symfony Console — barres de progression, tables, helpers de questions — et ils étaient corrects. Fonctionnels. Pas beaux. Juste corrects.
Laravel Prompts a changé cette trajectoire quand il a été lancé en 2023 avec Laravel 10. Mais la version initiale était focalisée sur l'entrée — text, select, multiselect, confirm. Obtenir des informations de l'utilisateur de manière soignée. Le côté sortie — montrer des informations à l'utilisateur pendant les opérations — restait basique. $this->info() et $this->error() et l'occasionnelle barre de progression.
v0.3.15 complète le tableau. Entrée et sortie sont désormais des préoccupations de première classe. Vous pouvez construire une expérience CLI qui rivalise avec ce que vous attendriez d'un outil Node.js construit avec Ink ou d'un outil Rust construit avec Ratatui. Spinners, texte en streaming, labels qui se mettent à jour en direct, messages de statut persistants, notifications natives, gestion des titres de terminal — ce sont les briques de base qui séparent une « commande » d'une « expérience ».
Et le fait qu'ils aient été extraits du Cloud CLI signifie qu'ils ont déjà survécu au test le plus difficile : de vrais ingénieurs les utilisant chaque jour dans des conditions réelles. Le spinner devait être fluide. Le défilement du log devait gérer une sortie rapide sans scintillement. Les notifications devaient réellement apparaître de manière fiable sur macOS, Linux et WSL. Ce ne sont pas des fonctionnalités théoriques — ce sont des fonctionnalités éprouvées en production.
Pour l'écosystème Laravel spécifiquement, je pense que cette version marque un tournant. Les commandes Artisan ont toujours été puissantes côté logique. Maintenant elles peuvent être puissantes côté expérience aussi. Et dans une ère où les développeurs choisissent de plus en plus leurs outils en fonction de ce qu'ils ressentent à l'usage — pas seulement de ce qu'ils font — cette distinction compte plus que la plupart des gens ne le réalisent.
Ce Que Je Veux Voir Ensuite
Les primitives sont là. La fondation est solide. Mais il y a des lacunes que je surveille.
Des layouts composables. Le composant Grid de la v0.3.10 est un début, mais je veux la possibilité de placer un spinner task() à côté d'une table() qui se met à jour en temps réel. Des éléments côte à côte. Des layouts style tableau de bord. Le Cloud CLI a probablement une partie de cela en interne — j'espère que davantage en sera extrait.
Des raccourcis clavier dans les tâches. Imaginez appuyer sur « v » pour basculer le logging verbeux, ou « s » pour sauter l'étape en cours. Des tâches interactives, pas seulement des tâches en lecture seule. L'extension pcntl permet déjà la gestion des signaux — l'étendre à la détection des touches au sein d'une tâche en cours d'exécution semble être la prochaine étape naturelle.
Le support des thèmes. Le rendu actuel est magnifique, mais c'est une esthétique unique. Différents projets ont différents environnements de terminal. Une API de thèmes — même une simple qui vous permet de surcharger les couleurs et les symboles — rendrait Prompts natif dans la configuration d'outils de n'importe quelle équipe.
Rien de tout cela n'est une critique. v0.3.15 est une version véritablement solide. Mais la trajectoire qu'elle établit est sans doute plus excitante que ce qu'elle a livré. L'écart entre « outil CLI PHP » et « application terminal soignée » vient de se réduire considérablement.
Commencez Par Une Commande
Choisissez une commande Artisan dans votre projet — celle qui prend le plus de temps, celle qui produit le plus de texte, celle que votre équipe évite de lancer parce que l'expérience est pénible. Réécrivez-la avec task(). Ajoutez un notify() à la fin. Définissez le title() au début.
Ça vous prendra 30 minutes. La commande fera exactement la même chose qu'avant. Mais elle semblera être un outil différent. Et la prochaine fois que quelqu'un dans votre équipe la lancera, il le remarquera. C'est le genre d'amélioration qui ne coûte rien et qui change tout dans la perception de vos outils.
Les primitives sont là. Composer les a déjà :
composer require laravel/prompts:^0.3.15
Ou si vous êtes sur Laravel 12 ou 13, elles sont déjà incluses. Commencez simplement à utiliser les fonctions.
Une commande. Trente minutes. Allez-y.
Questions Fréquemment Posées
Est-ce que task() de Laravel Prompts fonctionne sur Windows ?
La fonction task() fonctionne sur toutes les plateformes, mais le spinner animé nécessite l'extension PHP PCNTL, qui n'est pas disponible sur Windows natif. Sur Windows, un rendu statique de repli s'affiche à la place. Utiliser WSL sur Windows vous donne un support complet de l'animation puisqu'il exécute un vrai noyau Linux.
Quelle est la différence entre spin() et task() dans Laravel Prompts ?
spin() est pour les opérations simples en une seule étape où vous avez besoin d'un spinner et d'un message. task() est pour les opérations multi-phases avec une sortie de log défilante, des mises à jour dynamiques de label et des messages persistants de succès/avertissement/erreur. Utilisez spin() pour les appels API rapides de moins de 10 secondes ; utilisez task() pour les déploiements, migrations et builds multi-étapes.
Puis-je utiliser stream() de Laravel Prompts pour du texte généré par IA ?
Oui — stream() a été conçu spécifiquement pour ce cas d'usage. Appelez $stream->append() avec chaque chunk d'une réponse en streaming d'une API LLM, et le texte se rend avec un effet d'apparition progressive. Appelez $stream->close() quand le stream se termine pour finaliser la sortie et restaurer le curseur.
Quelle version de PHP Laravel Prompts v0.3.15 nécessite-t-il ?
Laravel Prompts v0.3.15 nécessite PHP 8.1 ou supérieur et l'extension ext-mbstring. Il fonctionne avec Symfony Console 6.2, 7.0 et 8.0, et est inclus avec Laravel 12 et Laravel 13.
Comment envoyer des notifications de bureau depuis une commande Artisan Laravel ?
Utilisez la fonction notify() de Laravel Prompts v0.3.15 : notify(title: 'Done', body: 'Your task finished.'). Elle envoie une notification native du système d'exploitation sur macOS (Centre de Notifications), Linux (daemon de notifications) et Windows via WSL. Aucun package ni configuration supplémentaire requis.
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