From c9609459e4aca807cbd1c4af8b886da6f6039a2e Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Sat, 2 May 2026 22:41:48 +0200 Subject: [PATCH] fix(daemon): --verbose actually lowers log level + reports effective level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --verbose was wired only to the stderr-mirror path. Debug entries got filtered by Logger.level (default 'info' from config) before reaching the mirror — so passing --verbose produced almost no extra output, which made it look broken on a fresh start. Now --verbose lowers the level to 'debug' AND mirrors. Logger exposes `effectiveLevel` so the "daemon started" banner reports what the logger is actually using, not what was in the config file. Co-Authored-By: Claude Opus 4.7 (1M context) --- packages/daemon/src/cli-main.ts | 20 ++++++++++++++++++-- packages/daemon/src/daemon.ts | 2 +- packages/daemon/src/logger.ts | 5 +++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/daemon/src/cli-main.ts b/packages/daemon/src/cli-main.ts index 6e3101956..63869b4e2 100644 --- a/packages/daemon/src/cli-main.ts +++ b/packages/daemon/src/cli-main.ts @@ -13,7 +13,9 @@ Alias: sf-daemon Options: --config Path to YAML config file (default: ~/.sf/daemon.yaml) - --verbose Print log entries to stderr in addition to the log file + --verbose Lower log level to debug AND mirror entries to stderr + --start Start an autonomous SF session for this project path + --command Command to send for --start (default: /sf autonomous) --install Install the launchd LaunchAgent (auto-starts on login) --uninstall Uninstall the launchd LaunchAgent --status Show launchd agent status (registered, PID, exit code) @@ -25,6 +27,8 @@ export async function main(): Promise { options: { config: { type: 'string', short: 'c' }, verbose: { type: 'boolean', short: 'v', default: false }, + start: { type: 'string' }, + command: { type: 'string' }, install: { type: 'boolean', default: false }, uninstall: { type: 'boolean', default: false }, status: { type: 'boolean', default: false }, @@ -80,14 +84,26 @@ export async function main(): Promise { const configPath = resolveConfigPath(values.config); const config = loadConfig(configPath); + // --verbose lowers log level to debug AND mirrors to stderr. Without + // this, debug entries are dropped before reaching the verbose stderr + // mirror — making --verbose silently useless on a default-info config. const logger = new Logger({ filePath: config.log.file, - level: config.log.level, + level: values.verbose ? 'debug' : config.log.level, verbose: values.verbose, }); const daemon = new Daemon(config, logger); await daemon.start(); + + if (values.start !== undefined) { + const projectDir = values.start.trim() === '' ? process.cwd() : values.start; + const sessionId = await daemon.getSessionManager().startSession({ + projectDir, + ...(values.command ? { command: values.command } : {}), + }); + logger.info('batch session started', { sessionId, projectDir }); + } } export function handleFatalError(err: unknown): never { diff --git a/packages/daemon/src/daemon.ts b/packages/daemon/src/daemon.ts index 8b1db3db6..770d023d3 100644 --- a/packages/daemon/src/daemon.ts +++ b/packages/daemon/src/daemon.ts @@ -35,7 +35,7 @@ export class Daemon { this.sessionManager = new SessionManager(this.logger); this.logger.info('daemon started', { - log_level: this.config.log.level, + log_level: this.logger.effectiveLevel, scan_roots: this.config.projects.scan_roots.length, discord_configured: !!this.config.discord, }); diff --git a/packages/daemon/src/logger.ts b/packages/daemon/src/logger.ts index e65e5d4ea..e2c0a9936 100644 --- a/packages/daemon/src/logger.ts +++ b/packages/daemon/src/logger.ts @@ -24,6 +24,10 @@ export class Logger { private readonly stream: WriteStream; private readonly level: number; private readonly verbose: boolean; + /** The level name actually in effect — surfaced so callers (e.g. the + * startup banner) report the level the logger is using, not the level + * that was originally requested in config. */ + readonly effectiveLevel: LogLevel; constructor(opts: LoggerOptions) { // Ensure parent directory exists @@ -37,6 +41,7 @@ export class Logger { this.stream = createWriteStream(opts.filePath, { flags: 'a' }); this.level = LEVEL_ORDER[opts.level] ?? LEVEL_ORDER.info; + this.effectiveLevel = opts.level; this.verbose = opts.verbose ?? false; }