glugox / action-runner
Headless action runner for Laravel that executes Artisan commands or Nova-like actions, stores logs and progress, and broadcasts output in real time.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/glugox/action-runner
Requires
- php: ^8.1
- illuminate/broadcasting: ^12.0
- illuminate/database: ^12.0
- illuminate/events: ^12.0
- illuminate/routing: ^12.0
- illuminate/support: ^12.0
- symfony/process: ^7.3.4
Requires (Dev)
- nunomaduro/collision: ^8.8.2
- orchestra/testbench: ^10.6.0
- pestphp/pest: ^4.1.2
- pestphp/pest-plugin-laravel: ^4.0.0
This package is auto-updated.
Last update: 2025-10-20 23:29:24 UTC
README
Headless Laravel package to execute Artisan commands or Laravel Nova-like model actions, persist logs + progress to DB, and broadcast real-time output so any frontend (Vue/React/Inertia) can render consoles and progress bars.
Install
composer require glugox/action-runner
php artisan vendor:publish --provider="Glugox\\ActionRunner\\ActionRunnerServiceProvider" --tag=migrations
php artisan migrate
No UI shipped. Bring your own frontend and subscribe to broadcasts.
Publish the config if you need to customise the route prefix, middleware, or registered actions:
php artisan vendor:publish --provider="Glugox\\ActionRunner\\ActionRunnerServiceProvider" --tag=config
Registered actions act as an allow-list. Each entry's key is used in the HTTP API and maps to the action class plus the models it is allowed to target:
// config/action-runner.php 'actions' => [ 'publish-posts' => [ 'class' => App\\Actions\\PublishPosts::class, 'models' => [App\\Models\\Post::class], ], ],
⚠️ Keep these routes behind authentication/authorization middleware (e.g.
['api', 'auth:sanctum']
) to ensure only trusted clients can trigger them.
API
Run Artisan Command
POST /action-runner/run { "command": "cache:clear", "params": [] }
Run Nova-like Action
POST /action-runner/actions/run { "action": "publish-posts", "model": "App\\Models\\Post", "ids": [1, 2, 3], "fields": { "published_at": "2024-12-01" } }
Provide the
model
key when an action is registered for multiple models. If the action only supports a single model, the payload can omit themodel
property and it will default to the allowed class.
GET /action-runner/{id}/status
Broadcasting
Subscribe to channel action-runner.{id}
and listen for events:
.ActionOutputUpdated
→{ logId, line }
.ActionProgressUpdated
→{ logId, progress }
.ActionStatusChanged
→{ logId, status }
Reporting From Your Console Command or Action
use App\Models\Post; use Glugox\ActionRunner\ActionReporter; use Glugox\ActionRunner\Actions\Action; use Glugox\ActionRunner\Actions\ActionFields; use Glugox\ActionRunner\Actions\ActionResponse; use Illuminate\Http\Request; use Illuminate\Support\Collection; class ImportData extends \Illuminate\Console\Command { protected $signature = 'import:data'; public function handle() { ActionReporter::progress(10); ActionReporter::appendOutput('Starting import...'); // Work ... ActionReporter::progress(90); ActionReporter::appendOutput('Almost done'); ActionReporter::finish('success'); } } class PublishPosts extends Action { public function authorize(Request $request): bool { return $request->user()?->can('publish', Post::class) ?? false; } public function handle(ActionFields $fields, Collection $models): ActionResponse { $this->reportProgress(10); $models->each->update(['published_at' => $fields->get('published_at')]); $this->appendOutput('Posts published'); $this->markFinished(); return ActionResponse::success('Published ' . $models->count() . ' posts.'); } }
Testing
composer install ./vendor/bin/pest
This package uses Orchestra Testbench + Pest.
Queue Support
You can run actions asynchronously by passing "queued": true
in your request.
POST /action-runner/run { "command": "import:data", "params": [], "queued": true }
POST /action-runner/actions/run { "action": "publish-posts", "model": "App\\Models\\Post", "ids": [1, 2, 3], "queued": true }
- The response returns immediately with
status: pending
. - A
RunActionJob
orRunClassActionJob
is dispatched to Laravel's queue system. - Progress/output/status are updated via
ActionReporter
. - Make sure your queue worker is running:
php artisan queue:work
.