fix: macOS compatibility for status commands and gateway client id
Replace Linux-only commands (uptime -s, free -m, df --output=pcent) with cross-platform alternatives using process.platform detection and Node.js os module. Rename gateway client ID from control-ui to openclaw-control-ui. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4cb86bc80b
commit
d59b2e70a1
|
|
@ -65,7 +65,7 @@ NEXT_PUBLIC_GATEWAY_PROTOCOL=
|
|||
NEXT_PUBLIC_GATEWAY_URL=
|
||||
# NEXT_PUBLIC_GATEWAY_TOKEN= # Optional, set if gateway requires auth token
|
||||
# Gateway client id used in websocket handshake (role=operator UI client).
|
||||
NEXT_PUBLIC_GATEWAY_CLIENT_ID=control-ui
|
||||
NEXT_PUBLIC_GATEWAY_CLIENT_ID=openclaw-control-ui
|
||||
|
||||
# === Data Paths (all optional, defaults to .data/ in project root) ===
|
||||
# MISSION_CONTROL_DATA_DIR=.data
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { NextRequest, NextResponse } from 'next/server'
|
||||
import net from 'node:net'
|
||||
import os from 'node:os'
|
||||
import { existsSync, statSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { runCommand, runOpenClaw, runClawdbot } from '@/lib/command'
|
||||
|
|
@ -195,29 +196,48 @@ async function getSystemStatus(workspaceId: number) {
|
|||
}
|
||||
|
||||
try {
|
||||
// System uptime
|
||||
const { stdout: uptimeOutput } = await runCommand('uptime', ['-s'], {
|
||||
timeoutMs: 3000
|
||||
})
|
||||
const bootTime = new Date(uptimeOutput.trim())
|
||||
status.uptime = Date.now() - bootTime.getTime()
|
||||
// System uptime (cross-platform)
|
||||
if (process.platform === 'darwin') {
|
||||
const { stdout } = await runCommand('sysctl', ['-n', 'kern.boottime'], {
|
||||
timeoutMs: 3000
|
||||
})
|
||||
// Output format: { sec = 1234567890, usec = 0 } ...
|
||||
const match = stdout.match(/sec\s*=\s*(\d+)/)
|
||||
if (match) {
|
||||
status.uptime = Date.now() - parseInt(match[1]) * 1000
|
||||
}
|
||||
} else {
|
||||
const { stdout } = await runCommand('uptime', ['-s'], {
|
||||
timeoutMs: 3000
|
||||
})
|
||||
const bootTime = new Date(stdout.trim())
|
||||
status.uptime = Date.now() - bootTime.getTime()
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error({ err: error }, 'Error getting uptime')
|
||||
}
|
||||
|
||||
try {
|
||||
// Memory info
|
||||
const { stdout: memOutput } = await runCommand('free', ['-m'], {
|
||||
timeoutMs: 3000
|
||||
})
|
||||
const memLines = memOutput.split('\n')
|
||||
const memLine = memLines.find(line => line.startsWith('Mem:'))
|
||||
if (memLine) {
|
||||
const parts = memLine.split(/\s+/)
|
||||
status.memory = {
|
||||
total: parseInt(parts[1]) || 0,
|
||||
used: parseInt(parts[2]) || 0,
|
||||
available: parseInt(parts[6]) || 0
|
||||
// Memory info (cross-platform)
|
||||
if (process.platform === 'darwin') {
|
||||
const totalBytes = os.totalmem()
|
||||
const freeBytes = os.freemem()
|
||||
const totalMB = Math.round(totalBytes / (1024 * 1024))
|
||||
const usedMB = Math.round((totalBytes - freeBytes) / (1024 * 1024))
|
||||
const availableMB = Math.round(freeBytes / (1024 * 1024))
|
||||
status.memory = { total: totalMB, used: usedMB, available: availableMB }
|
||||
} else {
|
||||
const { stdout: memOutput } = await runCommand('free', ['-m'], {
|
||||
timeoutMs: 3000
|
||||
})
|
||||
const memLine = memOutput.split('\n').find(line => line.startsWith('Mem:'))
|
||||
if (memLine) {
|
||||
const parts = memLine.split(/\s+/)
|
||||
status.memory = {
|
||||
total: parseInt(parts[1]) || 0,
|
||||
used: parseInt(parts[2]) || 0,
|
||||
available: parseInt(parts[6]) || 0
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
@ -414,14 +434,17 @@ async function performHealthCheck() {
|
|||
})
|
||||
}
|
||||
|
||||
// Check disk space
|
||||
// Check disk space (cross-platform: use df -h / and parse capacity column)
|
||||
try {
|
||||
const { stdout } = await runCommand('df', ['/', '--output=pcent'], {
|
||||
const { stdout } = await runCommand('df', ['-h', '/'], {
|
||||
timeoutMs: 3000
|
||||
})
|
||||
const lines = stdout.trim().split('\n')
|
||||
const last = lines[lines.length - 1] || ''
|
||||
const usagePercent = parseInt(last.replace('%', '').trim() || '0')
|
||||
const parts = last.split(/\s+/)
|
||||
// On macOS capacity is col 4 ("85%"), on Linux use% is col 4 as well
|
||||
const pctField = parts.find(p => p.endsWith('%')) || '0%'
|
||||
const usagePercent = parseInt(pctField.replace('%', '') || '0')
|
||||
|
||||
health.checks.push({
|
||||
name: 'Disk Space',
|
||||
|
|
@ -436,15 +459,21 @@ async function performHealthCheck() {
|
|||
})
|
||||
}
|
||||
|
||||
// Check memory usage
|
||||
// Check memory usage (cross-platform)
|
||||
try {
|
||||
const { stdout } = await runCommand('free', ['-m'], { timeoutMs: 3000 })
|
||||
const lines = stdout.split('\n')
|
||||
const memLine = lines.find((line) => line.startsWith('Mem:'))
|
||||
const parts = (memLine || '').split(/\s+/)
|
||||
const total = parseInt(parts[1] || '0')
|
||||
const available = parseInt(parts[6] || '0')
|
||||
const usagePercent = Math.round(((total - available) / total) * 100)
|
||||
let usagePercent: number
|
||||
if (process.platform === 'darwin') {
|
||||
const totalBytes = os.totalmem()
|
||||
const freeBytes = os.freemem()
|
||||
usagePercent = Math.round(((totalBytes - freeBytes) / totalBytes) * 100)
|
||||
} else {
|
||||
const { stdout } = await runCommand('free', ['-m'], { timeoutMs: 3000 })
|
||||
const memLine = stdout.split('\n').find((line) => line.startsWith('Mem:'))
|
||||
const parts = (memLine || '').split(/\s+/)
|
||||
const total = parseInt(parts[1] || '0')
|
||||
const available = parseInt(parts[6] || '0')
|
||||
usagePercent = Math.round(((total - available) / total) * 100)
|
||||
}
|
||||
|
||||
health.checks.push({
|
||||
name: 'Memory Usage',
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const log = createClientLogger('WebSocket')
|
|||
|
||||
// Gateway protocol version (v3 required by OpenClaw 2026.x)
|
||||
const PROTOCOL_VERSION = 3
|
||||
const DEFAULT_GATEWAY_CLIENT_ID = process.env.NEXT_PUBLIC_GATEWAY_CLIENT_ID || 'control-ui'
|
||||
const DEFAULT_GATEWAY_CLIENT_ID = process.env.NEXT_PUBLIC_GATEWAY_CLIENT_ID || 'openclaw-control-ui'
|
||||
|
||||
// Heartbeat configuration
|
||||
const PING_INTERVAL_MS = 30_000
|
||||
|
|
|
|||
Loading…
Reference in New Issue