- Add journalctl_recent command and scrum4me-web to whitelist in commands.yml.example - Add SYSTEMD_UNITS env var to .env.example - lib/parse-systemd.ts: parse activeState, subState, uptime, description - /app/systemd: server page reading SYSTEMD_UNITS, client list with 10s polling and status badges - /app/systemd/[unit]: server detail page, client component showing systemctl status + last 100 journal lines (polling 10s) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
34 lines
1.2 KiB
TypeScript
34 lines
1.2 KiB
TypeScript
export type ActiveState = 'active' | 'inactive' | 'failed' | 'activating' | 'deactivating' | 'unknown'
|
|
|
|
export interface UnitStatus {
|
|
activeState: ActiveState
|
|
subState: string
|
|
uptime: string
|
|
description: string
|
|
}
|
|
|
|
const KNOWN_STATES = new Set(['active', 'inactive', 'failed', 'activating', 'deactivating'])
|
|
|
|
export function parseSystemctlStatus(output: string, unitName: string): UnitStatus {
|
|
let activeState: ActiveState = 'unknown'
|
|
let subState = ''
|
|
let uptime = ''
|
|
let description = unitName
|
|
|
|
for (const line of output.split('\n')) {
|
|
// Header line: "● scrum4me-web.service - Description text"
|
|
const headerMatch = line.match(/^\s*[●○×◉]\s+\S+\s+-\s+(.+)/)
|
|
if (headerMatch) description = headerMatch[1].trim()
|
|
|
|
// Active line: " Active: active (running) since Tue 2025-01-13...; 2h 30min ago"
|
|
const activeMatch = line.match(/\bActive:\s+(\w+)(?:\s+\(([^)]+)\))?(?:.*?;\s+(.+?ago))?/)
|
|
if (activeMatch) {
|
|
const state = activeMatch[1].toLowerCase()
|
|
activeState = KNOWN_STATES.has(state) ? (state as ActiveState) : 'unknown'
|
|
subState = activeMatch[2] ?? ''
|
|
uptime = activeMatch[3] ?? ''
|
|
}
|
|
}
|
|
|
|
return { activeState, subState, uptime, description }
|
|
}
|