fix: persistent daemon startup, plugin integration, mobile fallback
- Hook handler now loads .env.daemon for proper config (plugin URL/secret, bot user ID) - Hook logs to /tmp/status-watcher.log instead of /dev/null - Added .env.daemon config file (.gitignored - contains tokens) - Added start-daemon.sh convenience script - Plugin mode: mobile fallback updates post message field with formatted markdown - Fixed unbounded lines array in status-watcher (capped at 50) - Added session marker to formatter output for restart recovery - Go plugin: added updatePostMessageForMobile() for dual-render strategy (webapp gets custom React component, mobile gets markdown in message field) Fixes: daemon silently dying, no plugin connection, mobile showing blank posts
This commit is contained in:
@@ -22,6 +22,9 @@ const { spawn } = require('child_process');
|
||||
// PID file location (must match watcher-manager.js default)
|
||||
const PID_FILE = process.env.PID_FILE || '/tmp/status-watcher.pid';
|
||||
|
||||
// Log file location
|
||||
const LOG_FILE = process.env.LIVESTATUS_LOG_FILE || '/tmp/status-watcher.log';
|
||||
|
||||
// Path to watcher-manager.js (relative to this hook file's location)
|
||||
// Hook is in: workspace/hooks/status-watcher-hook/handler.js
|
||||
// Watcher is in: workspace/projects/openclaw-live-status/src/watcher-manager.js
|
||||
@@ -30,6 +33,12 @@ const WATCHER_PATH = path.resolve(
|
||||
'../../projects/openclaw-live-status/src/watcher-manager.js',
|
||||
);
|
||||
|
||||
// Path to .env.daemon config file
|
||||
const ENV_DAEMON_PATH = path.resolve(
|
||||
__dirname,
|
||||
'../../projects/openclaw-live-status/.env.daemon',
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if a process is alive given its PID.
|
||||
* Returns true if process exists and is running.
|
||||
@@ -60,6 +69,31 @@ function isWatcherRunning() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load .env.daemon file into an env object (key=value lines, ignoring comments).
|
||||
* Returns merged env: process.env + .env.daemon overrides.
|
||||
*/
|
||||
function loadDaemonEnv() {
|
||||
const env = Object.assign({}, process.env);
|
||||
try {
|
||||
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
||||
const content = fs.readFileSync(ENV_DAEMON_PATH, 'utf8');
|
||||
for (const line of content.split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||
const eqIdx = trimmed.indexOf('=');
|
||||
if (eqIdx <= 0) continue;
|
||||
const key = trimmed.slice(0, eqIdx).trim();
|
||||
const val = trimmed.slice(eqIdx + 1).trim();
|
||||
env[key] = val; // eslint-disable-line security/detect-object-injection
|
||||
}
|
||||
console.log('[status-watcher-hook] Loaded daemon config from', ENV_DAEMON_PATH);
|
||||
} catch (_err) {
|
||||
console.warn('[status-watcher-hook] No .env.daemon found at', ENV_DAEMON_PATH, '— using process.env only');
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn the watcher daemon as a detached background process.
|
||||
* The parent (this hook handler) does not wait for it.
|
||||
@@ -73,14 +107,32 @@ function spawnWatcher() {
|
||||
|
||||
console.log('[status-watcher-hook] Starting Live Status v4 watcher daemon...');
|
||||
|
||||
// Load .env.daemon for proper config (plugin URL/secret, bot user ID, etc.)
|
||||
const daemonEnv = loadDaemonEnv();
|
||||
|
||||
// Open log file for append — never /dev/null
|
||||
let logFd;
|
||||
try {
|
||||
logFd = fs.openSync(LOG_FILE, 'a');
|
||||
console.log('[status-watcher-hook] Logging to', LOG_FILE);
|
||||
} catch (err) {
|
||||
console.error('[status-watcher-hook] Cannot open log file', LOG_FILE, ':', err.message);
|
||||
logFd = 'ignore';
|
||||
}
|
||||
|
||||
const child = spawn(process.execPath, [WATCHER_PATH, 'start'], {
|
||||
detached: true,
|
||||
stdio: 'ignore',
|
||||
env: process.env,
|
||||
stdio: ['ignore', logFd, logFd],
|
||||
env: daemonEnv,
|
||||
});
|
||||
|
||||
child.unref();
|
||||
|
||||
// Close the fd in the parent process (child inherits its own copy)
|
||||
if (typeof logFd === 'number') {
|
||||
try { fs.closeSync(logFd); } catch (_e) { /* ignore */ }
|
||||
}
|
||||
|
||||
console.log(
|
||||
'[status-watcher-hook] Watcher daemon spawned (PID will be written to',
|
||||
PID_FILE + ')',
|
||||
|
||||
Reference in New Issue
Block a user