From c98f5e6a1f5e6075c8693e71aa40c7f158761644 Mon Sep 17 00:00:00 2001 From: Yaojia Wang Date: Sun, 19 Jul 2026 07:57:22 +0200 Subject: [PATCH] fix(agent): give launchd units a log sink (StandardOut/ErrorPath) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit launchd has no default log destination (unlike systemd's journald), so a unit that fails to start (bare node, missing env) was silent — which hid the EX_CONFIG + loadConfig failures during this deploy. Route both units' stdout+stderr to /{base-app,agent}.log. 281 tests pass. --- agent/src/service/install.ts | 12 +++++++++--- agent/src/service/launchd.ts | 11 +++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/agent/src/service/install.ts b/agent/src/service/install.ts index adae58e..8563098 100644 --- a/agent/src/service/install.ts +++ b/agent/src/service/install.ts @@ -11,7 +11,7 @@ * - FIX M-host-2service: base-app env (BIND_HOST/ALLOWED_ORIGINS/PORT/…) is routed to the * base-app unit ONLY; the agent unit (which supervises frpc) never carries it. */ -import { dirname } from 'node:path' +import { dirname, join } from 'node:path' import type { AgentConfig } from '../config/agentConfig.js' import { agentLabel, @@ -225,9 +225,15 @@ export async function installService( if (platform === 'launchd') { const baseAppPath = launchdPlistPath(deps.homedir(), baseAppLabel()) - deps.writeFile(baseAppPath, buildLaunchdPlist(baseAppExec, baseAppEnvWithPath, baseAppLabel())) + deps.writeFile( + baseAppPath, + buildLaunchdPlist(baseAppExec, baseAppEnvWithPath, baseAppLabel(), join(cfg.stateDir, 'base-app.log')), + ) const agentPath = launchdPlistPath(deps.homedir(), agentLabel()) - deps.writeFile(agentPath, buildLaunchdPlist([nodePath, bin, 'run'], agentEnv, agentLabel())) + deps.writeFile( + agentPath, + buildLaunchdPlist([nodePath, bin, 'run'], agentEnv, agentLabel(), join(cfg.stateDir, 'agent.log')), + ) for (const path of [baseAppPath, agentPath]) { const { cmd, args } = launchdLoadCommand(path) await deps.runCommand(cmd, args) diff --git a/agent/src/service/launchd.ts b/agent/src/service/launchd.ts index b4d1e76..772ca4b 100644 --- a/agent/src/service/launchd.ts +++ b/agent/src/service/launchd.ts @@ -78,6 +78,7 @@ export function buildLaunchdPlist( programArguments: readonly string[], env: ServiceEnv = {}, label: string = AGENT_LABEL, + logPath?: string, ): string { return [ '', @@ -91,6 +92,16 @@ export function buildLaunchdPlist( ' ', ' KeepAlive', ' ', + // launchd's default has no log sink (unlike systemd's journald), so a crashing unit is silent. + // Route stdout+stderr to a file so `pair --install` failures are diagnosable out of the box. + ...(logPath !== undefined + ? [ + ' StandardOutPath', + ` ${escapeXml(logPath)}`, + ' StandardErrorPath', + ` ${escapeXml(logPath)}`, + ] + : []), ...environmentVariablesBlock(env), '', '',