diff --git a/src/daemon/launchd.ts b/src/daemon/launchd.ts index b11a2d9e01f..914f2a4e007 100644 --- a/src/daemon/launchd.ts +++ b/src/daemon/launchd.ts @@ -11,7 +11,7 @@ import { buildLaunchAgentPlist as buildLaunchAgentPlistImpl, readLaunchAgentProgramArgumentsFromFile, } from "./launchd-plist.js"; -import { formatLine, toPosixPath } from "./output.js"; +import { formatLine, toPosixPath, writeFormattedLines } from "./output.js"; import { resolveGatewayStateDir, resolveHomeDir } from "./paths.js"; import { parseKeyValueOutput } from "./runtime-parse.js"; import type { GatewayServiceRuntime } from "./service-runtime.js"; @@ -407,9 +407,14 @@ export async function installLaunchAgent({ await execLaunchctl(["kickstart", "-k", `${domain}/${label}`]); // Ensure we don't end up writing to a clack spinner line (wizards show progress without a newline). - stdout.write("\n"); - stdout.write(`${formatLine("Installed LaunchAgent", plistPath)}\n`); - stdout.write(`${formatLine("Logs", stdoutPath)}\n`); + writeFormattedLines( + stdout, + [ + { label: "Installed LaunchAgent", value: plistPath }, + { label: "Logs", value: stdoutPath }, + ], + { leadingBlankLine: true }, + ); return { plistPath }; } diff --git a/src/daemon/output.ts b/src/daemon/output.ts index 900f61184f1..0d910918c2b 100644 --- a/src/daemon/output.ts +++ b/src/daemon/output.ts @@ -6,3 +6,16 @@ export function formatLine(label: string, value: string): string { const rich = isRich(); return `${colorize(rich, theme.muted, `${label}:`)} ${colorize(rich, theme.command, value)}`; } + +export function writeFormattedLines( + stdout: NodeJS.WritableStream, + lines: Array<{ label: string; value: string }>, + opts?: { leadingBlankLine?: boolean }, +): void { + if (opts?.leadingBlankLine) { + stdout.write("\n"); + } + for (const line of lines) { + stdout.write(`${formatLine(line.label, line.value)}\n`); + } +} diff --git a/src/daemon/schtasks.ts b/src/daemon/schtasks.ts index a24503e55ac..b1c325276ea 100644 --- a/src/daemon/schtasks.ts +++ b/src/daemon/schtasks.ts @@ -2,7 +2,7 @@ import fs from "node:fs/promises"; import path from "node:path"; import { splitArgsPreservingQuotes } from "./arg-split.js"; import { resolveGatewayServiceDescription, resolveGatewayWindowsTaskName } from "./constants.js"; -import { formatLine } from "./output.js"; +import { formatLine, writeFormattedLines } from "./output.js"; import { resolveGatewayStateDir } from "./paths.js"; import { parseKeyValueOutput } from "./runtime-parse.js"; import { execSchtasks } from "./schtasks-exec.js"; @@ -230,9 +230,14 @@ export async function installScheduledTask({ await execSchtasks(["/Run", "/TN", taskName]); // Ensure we don't end up writing to a clack spinner line (wizards show progress without a newline). - stdout.write("\n"); - stdout.write(`${formatLine("Installed Scheduled Task", taskName)}\n`); - stdout.write(`${formatLine("Task script", scriptPath)}\n`); + writeFormattedLines( + stdout, + [ + { label: "Installed Scheduled Task", value: taskName }, + { label: "Task script", value: scriptPath }, + ], + { leadingBlankLine: true }, + ); return { scriptPath }; } diff --git a/src/daemon/systemd.ts b/src/daemon/systemd.ts index 23e035e1d2a..6fad14034a5 100644 --- a/src/daemon/systemd.ts +++ b/src/daemon/systemd.ts @@ -6,7 +6,7 @@ import { resolveGatewaySystemdServiceName, } from "./constants.js"; import { execFileUtf8 } from "./exec-file.js"; -import { formatLine, toPosixPath } from "./output.js"; +import { formatLine, toPosixPath, writeFormattedLines } from "./output.js"; import { resolveHomeDir } from "./paths.js"; import { parseKeyValueOutput } from "./runtime-parse.js"; import type { GatewayServiceRuntime } from "./service-runtime.js"; @@ -227,8 +227,16 @@ export async function installSystemdService({ } // Ensure we don't end up writing to a clack spinner line (wizards show progress without a newline). - stdout.write("\n"); - stdout.write(`${formatLine("Installed systemd service", unitPath)}\n`); + writeFormattedLines( + stdout, + [ + { + label: "Installed systemd service", + value: unitPath, + }, + ], + { leadingBlankLine: true }, + ); return { unitPath }; }