From 351db0632d97d78e36d158cfdeb74807e1ac3530 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 1 Jan 2026 17:30:24 +0000 Subject: [PATCH] fix(signal): map stderr INFO to log --- src/signal/daemon.test.ts | 23 +++++++++++++++++++++++ src/signal/daemon.ts | 22 ++++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 src/signal/daemon.test.ts diff --git a/src/signal/daemon.test.ts b/src/signal/daemon.test.ts new file mode 100644 index 000000000..4940fc8b7 --- /dev/null +++ b/src/signal/daemon.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it } from "vitest"; + +import { classifySignalCliLogLine } from "./daemon.js"; + +describe("classifySignalCliLogLine", () => { + it("treats INFO/DEBUG as log (even if emitted on stderr)", () => { + expect(classifySignalCliLogLine("INFO DaemonCommand - Started")).toBe( + "log", + ); + expect(classifySignalCliLogLine("DEBUG Something")).toBe("log"); + }); + + it("treats WARN/ERROR as error", () => { + expect(classifySignalCliLogLine("WARN Something")).toBe("error"); + expect(classifySignalCliLogLine("WARNING Something")).toBe("error"); + expect(classifySignalCliLogLine("ERROR Something")).toBe("error"); + }); + + it("returns null for empty lines", () => { + expect(classifySignalCliLogLine("")).toBe(null); + expect(classifySignalCliLogLine(" ")).toBe(null); + }); +}); diff --git a/src/signal/daemon.ts b/src/signal/daemon.ts index 9bbc61189..0bd382f9c 100644 --- a/src/signal/daemon.ts +++ b/src/signal/daemon.ts @@ -18,6 +18,14 @@ export type SignalDaemonHandle = { stop: () => void; }; +export function classifySignalCliLogLine(line: string): "log" | "error" | null { + const trimmed = line.trim(); + if (!trimmed) return null; + // signal-cli commonly writes all logs to stderr; treat severity explicitly. + if (/\b(ERROR|WARN|WARNING)\b/.test(trimmed)) return "error"; + return "log"; +} + function buildDaemonArgs(opts: SignalDaemonOpts): string[] { const args: string[] = []; if (opts.account) { @@ -46,12 +54,18 @@ export function spawnSignalDaemon(opts: SignalDaemonOpts): SignalDaemonHandle { const error = opts.runtime?.error ?? (() => {}); child.stdout?.on("data", (data) => { - const text = data.toString().trim(); - if (text) log(`signal-cli: ${text}`); + for (const line of data.toString().split(/\r?\n/)) { + const kind = classifySignalCliLogLine(line); + if (kind === "log") log(`signal-cli: ${line.trim()}`); + else if (kind === "error") error(`signal-cli: ${line.trim()}`); + } }); child.stderr?.on("data", (data) => { - const text = data.toString().trim(); - if (text) error(`signal-cli: ${text}`); + for (const line of data.toString().split(/\r?\n/)) { + const kind = classifySignalCliLogLine(line); + if (kind === "log") log(`signal-cli: ${line.trim()}`); + else if (kind === "error") error(`signal-cli: ${line.trim()}`); + } }); child.on("error", (err) => { error(`signal-cli spawn error: ${String(err)}`);