From 783a55a8c88d44636cee1cc869341ea1a282a643 Mon Sep 17 00:00:00 2001 From: edalzell Date: Thu, 11 Jun 2026 16:27:18 -0700 Subject: [PATCH 1/6] ability to disable title --- src/NewCommand.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/NewCommand.php b/src/NewCommand.php index 478b52d..3818ba6 100644 --- a/src/NewCommand.php +++ b/src/NewCommand.php @@ -90,7 +90,8 @@ protected function configure() ->addOption('repo', null, InputOption::VALUE_REQUIRED, 'Optionally specify the name of the GitHub repository') ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force install even if the directory already exists') ->addOption('email', null, InputOption::VALUE_OPTIONAL, 'Creates a super user with this email address') - ->addOption('password', null, InputOption::VALUE_OPTIONAL, 'Password for the super user'); + ->addOption('password', null, InputOption::VALUE_OPTIONAL, 'Password for the super user') + ->addOption('disable-title', null, InputOption::VALUE_NONE, "Don't show title art"); } protected function initialize(InputInterface $input, OutputInterface $output) @@ -327,6 +328,10 @@ protected function validateArguments() */ protected function showStatamicTitleArt() { + if ($this->input->hasOption('disable-title')) { + return $this; + } + $this->output->write(PHP_EOL.' █▀ ▀█▀ ▄▀█ ▀█▀ ▄▀█ █▀▄▀█ █ █▀▀ ▄█ ░█░ █▀█ ░█░ █▀█ █░▀░█ █ █▄▄'.PHP_EOL.PHP_EOL); From 7673ade0f6963ae85b2d9b2a95809adc1d70f384 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Wed, 29 Jul 2026 08:53:53 -0400 Subject: [PATCH 2/6] rename option --- src/NewCommand.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NewCommand.php b/src/NewCommand.php index 3818ba6..d9e3087 100644 --- a/src/NewCommand.php +++ b/src/NewCommand.php @@ -91,7 +91,7 @@ protected function configure() ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force install even if the directory already exists') ->addOption('email', null, InputOption::VALUE_OPTIONAL, 'Creates a super user with this email address') ->addOption('password', null, InputOption::VALUE_OPTIONAL, 'Password for the super user') - ->addOption('disable-title', null, InputOption::VALUE_NONE, "Don't show title art"); + ->addOption('no-ascii-art', null, InputOption::VALUE_NONE, "Don't show the ASCII art title"); } protected function initialize(InputInterface $input, OutputInterface $output) @@ -328,7 +328,7 @@ protected function validateArguments() */ protected function showStatamicTitleArt() { - if ($this->input->hasOption('disable-title')) { + if ($this->input->getOption('no-ascii-art')) { return $this; } From 7680b8d3bae7b16c28e2fcb91a5949e6743d83a8 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Thu, 30 Jul 2026 21:43:29 -0400 Subject: [PATCH 3/6] integrate laravel/prompts' task() into the install process Wrap the composer create-project and git init steps in RunsCommands with a Laravel Prompts task(), collapsing the raw scrolling output into a spinner that finishes as a single checkmark line, matching what the Laravel installer now does. Falls back to the existing raw output when task()/pcntl_fork aren't available or output isn't decorated. --- src/Concerns/RunsCommands.php | 47 ++++++++++++++++++++++++++++++++--- src/NewCommand.php | 4 +-- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/Concerns/RunsCommands.php b/src/Concerns/RunsCommands.php index 73dce94..e08d033 100644 --- a/src/Concerns/RunsCommands.php +++ b/src/Concerns/RunsCommands.php @@ -2,8 +2,12 @@ namespace Statamic\Cli\Concerns; +use Laravel\Prompts\Support\Logger; +use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; +use function Laravel\Prompts\task; + trait RunsCommands { /** @@ -11,9 +15,9 @@ trait RunsCommands * * @return Process */ - protected function runCommand(string $command, ?string $workingPath = null, bool $disableOutput = false) + protected function runCommand(string $command, ?string $workingPath = null, bool $disableOutput = false, ?string $taskLabel = null) { - return $this->runCommands([$command], $workingPath, $disableOutput); + return $this->runCommands([$command], $workingPath, $disableOutput, $taskLabel); } /** @@ -21,7 +25,7 @@ protected function runCommand(string $command, ?string $workingPath = null, bool * * @return Process */ - protected function runCommands(array $commands, ?string $workingPath = null, bool $disableOutput = false) + protected function runCommands(array $commands, ?string $workingPath = null, bool $disableOutput = false, ?string $taskLabel = null) { if (! $this->output->isDecorated()) { $commands = array_map(function ($value) { @@ -53,6 +57,10 @@ protected function runCommands(array $commands, ?string $workingPath = null, boo $process = Process::fromShellCommandline(implode(' && ', $commands), $workingPath, timeout: null); + if ($taskLabel && ! $disableOutput && $this->shouldRunAsTask()) { + return $this->runProcessAsTask($process, $taskLabel); + } + if ('\\' !== DIRECTORY_SEPARATOR && file_exists('/dev/tty') && is_readable('/dev/tty')) { try { if ($this->input->hasOption('no-interaction') && $this->input->getOption('no-interaction')) { @@ -75,4 +83,37 @@ protected function runCommands(array $commands, ?string $workingPath = null, boo return $process; } + + /** + * Determine if the process should be rendered as a collapsible Prompts task. + */ + private function shouldRunAsTask(): bool + { + return $this->output->getVerbosity() === OutputInterface::VERBOSITY_NORMAL + && $this->output->isDecorated() + && function_exists('Laravel\Prompts\task') + && function_exists('pcntl_fork'); + } + + /** + * Run the given process within a Laravel Prompts task, streaming its output into the task's log. + */ + private function runProcessAsTask(Process $process, string $taskLabel): Process + { + task( + label: $taskLabel, + keepSummary: true, + callback: function (Logger $logger) use ($process) { + $process->run(function ($type, $line) use ($logger) { + $logger->line($line); + }); + + if (! $process->isSuccessful()) { + $logger->error(trim($process->getErrorOutput())); + } + }, + ); + + return $process; + } } diff --git a/src/NewCommand.php b/src/NewCommand.php index d9e3087..033df03 100644 --- a/src/NewCommand.php +++ b/src/NewCommand.php @@ -507,7 +507,7 @@ protected function installBaseProject() $commands[] = "chmod 755 \"$this->absolutePath/please\""; } - $this->runCommands($commands); + $this->runCommands($commands, taskLabel: 'Installing Statamic'); if (! $this->wasBaseInstallSuccessful()) { throw new RuntimeException('There was a problem installing Statamic!'); @@ -835,7 +835,7 @@ protected function initializeGitRepository() "git branch -M {$branch}", ]; - $this->runCommands($commands, workingPath: $this->absolutePath); + $this->runCommands($commands, workingPath: $this->absolutePath, taskLabel: 'Initializing Git repository'); return $this; } From d65c966da6122e37c9351995038c0e6481ed3f55 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 9 Oct 2026 11:18:50 -0400 Subject: [PATCH 4/6] Only run as task when prompts supports keepSummary task() exists from laravel/prompts 0.3.15, but keepSummary was added in 0.3.17, so checking function_exists allowed a fatal error on 0.3.15/0.3.16. Co-Authored-By: Claude Opus 5.5 --- src/Concerns/RunsCommands.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Concerns/RunsCommands.php b/src/Concerns/RunsCommands.php index e08d033..cbd5a3b 100644 --- a/src/Concerns/RunsCommands.php +++ b/src/Concerns/RunsCommands.php @@ -3,6 +3,7 @@ namespace Statamic\Cli\Concerns; use Laravel\Prompts\Support\Logger; +use Laravel\Prompts\Task; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\Process; @@ -91,7 +92,7 @@ private function shouldRunAsTask(): bool { return $this->output->getVerbosity() === OutputInterface::VERBOSITY_NORMAL && $this->output->isDecorated() - && function_exists('Laravel\Prompts\task') + && property_exists(Task::class, 'keepSummary') && function_exists('pcntl_fork'); } From c7715b851789e962cb0d463825a7d5c0e927a05c Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 9 Oct 2026 11:24:52 -0400 Subject: [PATCH 5/6] Show full command output when a task fails Previously the entire stderr was passed to the logger as a single error, so only its first line was styled as the error and only the last 10 lines of output remained visible. Now a short error is logged and the full output is printed after the task. Co-Authored-By: Claude Opus 5.5 --- src/Concerns/RunsCommands.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Concerns/RunsCommands.php b/src/Concerns/RunsCommands.php index cbd5a3b..aceea9c 100644 --- a/src/Concerns/RunsCommands.php +++ b/src/Concerns/RunsCommands.php @@ -101,20 +101,27 @@ private function shouldRunAsTask(): bool */ private function runProcessAsTask(Process $process, string $taskLabel): Process { + $output = ''; + task( label: $taskLabel, keepSummary: true, - callback: function (Logger $logger) use ($process) { - $process->run(function ($type, $line) use ($logger) { + callback: function (Logger $logger) use ($process, &$output) { + $process->run(function ($type, $line) use ($logger, &$output) { + $output .= $line; $logger->line($line); }); if (! $process->isSuccessful()) { - $logger->error(trim($process->getErrorOutput())); + $logger->error("Failed with exit code {$process->getExitCode()}"); } }, ); + if (! $process->isSuccessful()) { + $this->output->write(PHP_EOL.preg_replace('/^/m', ' ', $output)); + } + return $process; } } From 7ca8e08c441f870597ff702c577e68293c34a885 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Fri, 9 Oct 2026 11:32:45 -0400 Subject: [PATCH 6/6] Remove --no-ascii-art option Out of scope for this PR. Co-Authored-By: Claude Opus 5.5 --- src/NewCommand.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/NewCommand.php b/src/NewCommand.php index 033df03..1457e46 100644 --- a/src/NewCommand.php +++ b/src/NewCommand.php @@ -90,8 +90,7 @@ protected function configure() ->addOption('repo', null, InputOption::VALUE_REQUIRED, 'Optionally specify the name of the GitHub repository') ->addOption('force', 'f', InputOption::VALUE_NONE, 'Force install even if the directory already exists') ->addOption('email', null, InputOption::VALUE_OPTIONAL, 'Creates a super user with this email address') - ->addOption('password', null, InputOption::VALUE_OPTIONAL, 'Password for the super user') - ->addOption('no-ascii-art', null, InputOption::VALUE_NONE, "Don't show the ASCII art title"); + ->addOption('password', null, InputOption::VALUE_OPTIONAL, 'Password for the super user'); } protected function initialize(InputInterface $input, OutputInterface $output) @@ -328,10 +327,6 @@ protected function validateArguments() */ protected function showStatamicTitleArt() { - if ($this->input->getOption('no-ascii-art')) { - return $this; - } - $this->output->write(PHP_EOL.' █▀ ▀█▀ ▄▀█ ▀█▀ ▄▀█ █▀▄▀█ █ █▀▀ ▄█ ░█░ █▀█ ░█░ █▀█ █░▀░█ █ █▄▄'.PHP_EOL.PHP_EOL);