darkfire514's picture
Upload 2526 files
fb4d8fe verified
import {
resolveGatewayLaunchAgentLabel,
resolveGatewaySystemdServiceName,
resolveGatewayWindowsTaskName,
} from "../../daemon/constants.js";
import { resolveGatewayLogPaths } from "../../daemon/launchd.js";
import { getResolvedLoggerSettings } from "../../logging.js";
import { formatCliCommand } from "../command-format.js";
export function parsePort(raw: unknown): number | null {
if (raw === undefined || raw === null) {
return null;
}
const value =
typeof raw === "string"
? raw
: typeof raw === "number" || typeof raw === "bigint"
? raw.toString()
: null;
if (value === null) {
return null;
}
const parsed = Number.parseInt(value, 10);
if (!Number.isFinite(parsed) || parsed <= 0) {
return null;
}
return parsed;
}
export function parsePortFromArgs(programArguments: string[] | undefined): number | null {
if (!programArguments?.length) {
return null;
}
for (let i = 0; i < programArguments.length; i += 1) {
const arg = programArguments[i];
if (arg === "--port") {
const next = programArguments[i + 1];
const parsed = parsePort(next);
if (parsed) {
return parsed;
}
}
if (arg?.startsWith("--port=")) {
const parsed = parsePort(arg.split("=", 2)[1]);
if (parsed) {
return parsed;
}
}
}
return null;
}
export function pickProbeHostForBind(
bindMode: string,
tailnetIPv4: string | undefined,
customBindHost?: string,
) {
if (bindMode === "custom" && customBindHost?.trim()) {
return customBindHost.trim();
}
if (bindMode === "tailnet") {
return tailnetIPv4 ?? "127.0.0.1";
}
return "127.0.0.1";
}
const SAFE_DAEMON_ENV_KEYS = [
"OPENCLAW_PROFILE",
"OPENCLAW_STATE_DIR",
"OPENCLAW_CONFIG_PATH",
"OPENCLAW_GATEWAY_PORT",
"OPENCLAW_NIX_MODE",
];
export function filterDaemonEnv(env: Record<string, string> | undefined): Record<string, string> {
if (!env) {
return {};
}
const filtered: Record<string, string> = {};
for (const key of SAFE_DAEMON_ENV_KEYS) {
const value = env[key];
if (!value?.trim()) {
continue;
}
filtered[key] = value.trim();
}
return filtered;
}
export function safeDaemonEnv(env: Record<string, string> | undefined): string[] {
const filtered = filterDaemonEnv(env);
return Object.entries(filtered).map(([key, value]) => `${key}=${value}`);
}
export function normalizeListenerAddress(raw: string): string {
let value = raw.trim();
if (!value) {
return value;
}
value = value.replace(/^TCP\s+/i, "");
value = value.replace(/\s+\(LISTEN\)\s*$/i, "");
return value.trim();
}
export function formatRuntimeStatus(
runtime:
| {
status?: string;
state?: string;
subState?: string;
pid?: number;
lastExitStatus?: number;
lastExitReason?: string;
lastRunResult?: string;
lastRunTime?: string;
detail?: string;
}
| undefined,
) {
if (!runtime) {
return null;
}
const status = runtime.status ?? "unknown";
const details: string[] = [];
if (runtime.pid) {
details.push(`pid ${runtime.pid}`);
}
if (runtime.state && runtime.state.toLowerCase() !== status) {
details.push(`state ${runtime.state}`);
}
if (runtime.subState) {
details.push(`sub ${runtime.subState}`);
}
if (runtime.lastExitStatus !== undefined) {
details.push(`last exit ${runtime.lastExitStatus}`);
}
if (runtime.lastExitReason) {
details.push(`reason ${runtime.lastExitReason}`);
}
if (runtime.lastRunResult) {
details.push(`last run ${runtime.lastRunResult}`);
}
if (runtime.lastRunTime) {
details.push(`last run time ${runtime.lastRunTime}`);
}
if (runtime.detail) {
details.push(runtime.detail);
}
return details.length > 0 ? `${status} (${details.join(", ")})` : status;
}
export function renderRuntimeHints(
runtime: { missingUnit?: boolean; status?: string } | undefined,
env: NodeJS.ProcessEnv = process.env,
): string[] {
if (!runtime) {
return [];
}
const hints: string[] = [];
const fileLog = (() => {
try {
return getResolvedLoggerSettings().file;
} catch {
return null;
}
})();
if (runtime.missingUnit) {
hints.push(`Service not installed. Run: ${formatCliCommand("openclaw gateway install", env)}`);
if (fileLog) {
hints.push(`File logs: ${fileLog}`);
}
return hints;
}
if (runtime.status === "stopped") {
if (fileLog) {
hints.push(`File logs: ${fileLog}`);
}
if (process.platform === "darwin") {
const logs = resolveGatewayLogPaths(env);
hints.push(`Launchd stdout (if installed): ${logs.stdoutPath}`);
hints.push(`Launchd stderr (if installed): ${logs.stderrPath}`);
} else if (process.platform === "linux") {
const unit = resolveGatewaySystemdServiceName(env.OPENCLAW_PROFILE);
hints.push(`Logs: journalctl --user -u ${unit}.service -n 200 --no-pager`);
} else if (process.platform === "win32") {
const task = resolveGatewayWindowsTaskName(env.OPENCLAW_PROFILE);
hints.push(`Logs: schtasks /Query /TN "${task}" /V /FO LIST`);
}
}
return hints;
}
export function renderGatewayServiceStartHints(env: NodeJS.ProcessEnv = process.env): string[] {
const base = [
formatCliCommand("openclaw gateway install", env),
formatCliCommand("openclaw gateway", env),
];
const profile = env.OPENCLAW_PROFILE;
switch (process.platform) {
case "darwin": {
const label = resolveGatewayLaunchAgentLabel(profile);
return [...base, `launchctl bootstrap gui/$UID ~/Library/LaunchAgents/${label}.plist`];
}
case "linux": {
const unit = resolveGatewaySystemdServiceName(profile);
return [...base, `systemctl --user start ${unit}.service`];
}
case "win32": {
const task = resolveGatewayWindowsTaskName(profile);
return [...base, `schtasks /Run /TN "${task}"`];
}
default:
return base;
}
}