botman/studio-addons
Official add-ons for BotMan Studio that extend Laravel-based chatbot projects with extra integrations, helpers, and configuration to speed up development.
This package shells out to the OS via Symfony\Component\Process\Process, so treat it as a thin, Laravel-friendly wrapper around external commands (artisan, git, ffmpeg, deploy scripts, backup tools) rather than as a domain library.
composer require <vendor>/<package> — the 1.6.1 release explicitly targets Laravel 7 and 8, so pin laravel/framework accordingly before upgrading an older app.config/<package>.php for binary paths, timeouts, and working-directory defaults. Most of the day-to-day knobs live there.Process first — that is where command construction, timeouts, and output handling are decided. Everything else in the package is usually glue.$process = new Process(['git', 'status', '--porcelain']);
$process->setTimeout(30);
$process->run();
if (! $process->isSuccessful()) {
throw new RuntimeException($process->getErrorOutput());
}
$changed = trim($process->getOutput()) !== '';
Because 1.6.1 fixes the Process constructor usage changed in Laravel 5.8, always pass the command as an array of arguments (or use Process::fromShellCommandline() when you genuinely need shell semantics). String commands still work in some paths but are the source of the exact bug this release patched.
Wrap it in a dedicated service, not in controllers. A CommandRunner / Shell class that takes the binary path and timeout from config keeps test doubles trivial and stops Process from leaking into HTTP handlers.
Prefer mustRun() inside queued jobs. run() swallows failure into an exit code you may forget to check; mustRun() throws ProcessFailedException and lets the queue's retry/backoff semantics do the work.
Stream output for long commands. Use run(function ($type, $buffer) { ... }) and forward to Log::info() or $this->output->write() in an artisan command, otherwise a hanging command looks identical to a slow one.
$process->run(fn ($type, $buffer) => Process::ERR === $type
? Log::warning($buffer)
: Log::info($buffer));
Compose with artisan rather than duplicating logic. If the external tool is another artisan command, call it via Artisan::call() or an array-based Process on PHP_BINARY . ' artisan' — consistent exit codes, consistent env.
Guard non-idempotent commands. Anything that mutates state (migrations, deploys, file moves) should be wrapped in a lock (Cache::lock()) before the process starts, since a retried job will happily run it twice.
Testing. Assert on the command array rather than shelling out — bind a fake runner in the container, or use Process::fake()-style abstractions if the package provides them. For integration tests, target a harmless binary (php -r 'exit(0);') so CI doesn't depend on system tooling.
Process API drift is the recurring pain point. Since Symfony 4.2/Laravel 5.8, the constructor expects an array; Process::fromShellCommandline() is the sanctioned escape hatch for pipes, redirects, and &&. If you are on this package purely for the 1.6.1 fix, audit your own call sites for the same pattern — the bug usually lives in your wrapper too.getOutput() / getErrorOutput() only after run()/start() completes, and remember getOutput() is cumulative and truncated unless you set setOutputDisabled(false) and read incrementally.setTimeout() produces ProcessTimedOutException; catch it explicitly if a slow tool is expected, or set setIdleTimeout() to kill only genuinely stalled processes.PATH and env differ between web and queue workers. A command that works in php artisan tinker can fail under FPM. Set the binary to an absolute path in config and pass an explicit env array to Process instead of relying on inheritance.rsync --progress, stream and discard rather than buffering the full string.Process::start() with manual isRunning() polling, or move to Laravel's queue with multiple workers, rather than trying to parallelise inside one request.How can I help you explore Laravel packages today?