call() - must use passthru for fresh process $this->prevent_call_from_another_command(); // Handle --force flag: complete clean and rebuild via exec if ($this->option('force')) { // Execute rsx:clean passthru('php artisan rsx:clean'); // Execute rsx:manifest:build without --force to avoid recursion passthru('php artisan rsx:manifest:build'); // Immediately exit die(); } // Check if in production mode with existing manifest if (config('app.env') === 'production') { $manifest_file = base_path('storage/rsx-build/manifest_data.php'); if (file_exists($manifest_file)) { $file_age = time() - filemtime($manifest_file); // If manifest exists and is older than 5 seconds, block rebuild if ($file_age > 5) { $this->error('Production manifest rebuild blocked'); $this->line(''); $this->line('The manifest file exists in production and is ' . round($file_age / 60, 1) . ' minutes old.'); $this->line('Rebuilding the manifest in production is not permitted without explicit confirmation.'); $this->line(''); $this->line('Use --force flag to override this protection and rebuild anyway.'); return 1; } } } $start_time = microtime(true); // Reset debug options Manifest::$_debug_options = []; // Handle --clean flag: clear caches first if ($this->option('clean')) { $this->info('๐Ÿงน Clearing caches before build...'); // Clear RSX caches (but not persistent directory) passthru('php artisan rsx:clean'); Manifest::clear(); } $this->info('Building RSX manifest...'); // Default behavior: incremental build (don't clear unless --clean was used) // Manifest::init() handles everything - loading cache and doing incremental updates Manifest::init(); $stats = Manifest::get_stats(); $elapsed = round((microtime(true) - $start_time) * 1000, 2); $this->info('Manifest built successfully!'); $this->line(''); $this->line('Summary:'); $this->line(' Build Hash: ' . Manifest::get_build_key()); $this->line(' Total Files: ' . $stats['total_files']); $this->line(' PHP Classes: ' . $stats['php']); $this->line(' JS Classes: ' . $stats['js']); $this->line(' Blade Views: ' . $stats['blade']); $this->line(' Build Time: ' . $elapsed . 'ms'); // Reset debug options Manifest::$_debug_options = []; return 0; } /** * Prevent this command from being called via $this->call() from another command * * This command MUST run in a fresh process to ensure in-memory caches are cleared. * Use passthru() instead of $this->call() when calling from other commands. * * @return void */ protected function prevent_call_from_another_command() { $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 20); foreach ($trace as $frame) { // Check if we're being called from Artisan::call() or Command::call() if (isset($frame['class']) && isset($frame['function'])) { $class = $frame['class']; $function = $frame['function']; // Detect $this->call() from another command if ($function === 'call' && str_contains($class, 'Command')) { $this->error(''); $this->error('โŒ FATAL ERROR: rsx:manifest:build cannot be called via $this->call()'); $this->error(''); $this->error('This command MUST run in a fresh process to properly clear in-memory caches.'); $this->error(''); $this->error('FIX: Use passthru() instead of $this->call():'); $this->error(''); $this->line(' // โŒ WRONG - runs in same process, caches remain in memory'); $this->line(' $this->call(\'rsx:manifest:build\');'); $this->error(''); $this->line(' // โœ… CORRECT - fresh process, all caches cleared'); $this->line(' passthru(\'php artisan rsx:manifest:build\');'); $this->error(''); exit(1); } } } } }