fix(logger): record warnings in debug.log

`log.warn` wrote to the console only and was muted in silent mode, so a
detached SessionStart pull, whose output is discarded, lost every warning:
the stub deploy failure and the legacy prune among them. Warnings now reach
debug.log like debug and error lines. `warnStubNotDeployed` drops the
second `log.debug` call, which printed the line twice under --verbose.
This commit is contained in:
Saul Moro
2026-09-23 14:03:59 +02:00
parent 79e4432bcf
commit b0583f5681
4 changed files with 17 additions and 10 deletions
+8
View File
@@ -45,6 +45,14 @@ describe('file transport', () => {
expect(fs.readFileSync(logFile, 'utf-8')).toContain('[ERROR] something broke');
});
it('writes warn to file, even when silent', () => {
// A detached SessionStart pull runs silent with its output discarded; its
// warnings must still leave a record.
setSilent(true);
log.warn('stub not deployed');
expect(fs.readFileSync(logFile, 'utf-8')).toContain('[WARN] stub not deployed');
});
it('includes timestamp', () => {
log.debug('ts');
expect(fs.readFileSync(logFile, 'utf-8').trim()).toMatch(/^\d{4}-\d{2}-\d{2}T/);
+4 -4
View File
@@ -319,8 +319,8 @@ describe('pull skip-sync when repo HEAD unchanged', () => {
expect(log.success).toHaveBeenCalledWith(expect.stringContaining('Already synced at abc1234, skipping'));
expect(log.warn).toHaveBeenCalledWith(expect.stringContaining('The built-in teamai skill was not deployed'));
expect(log.warn).toHaveBeenCalledWith(expect.stringContaining('EACCES: permission denied'));
// A SessionStart pull runs detached and silent; debug.log is its only record.
expect(log.debug).toHaveBeenCalledWith(expect.stringContaining('The built-in teamai skill was not deployed: EACCES: permission denied'));
// `log.warn` also records to debug.log; a second `log.debug` would print it twice under --verbose.
expect(log.debug).not.toHaveBeenCalledWith(expect.stringContaining('The built-in teamai skill was not deployed'));
});
it('warns when the built-in stub cannot be deployed on a full sync', async () => {
@@ -333,8 +333,8 @@ describe('pull skip-sync when repo HEAD unchanged', () => {
expect(log.warn).toHaveBeenCalledWith(expect.stringContaining('The built-in teamai skill was not deployed'));
expect(log.warn).toHaveBeenCalledWith(expect.stringContaining('EACCES: permission denied'));
// A SessionStart pull runs detached and silent; debug.log is its only record.
expect(log.debug).toHaveBeenCalledWith(expect.stringContaining('The built-in teamai skill was not deployed: EACCES: permission denied'));
// `log.warn` also records to debug.log; a second `log.debug` would print it twice under --verbose.
expect(log.debug).not.toHaveBeenCalledWith(expect.stringContaining('The built-in teamai skill was not deployed'));
});
it('should do full sync when HEAD rev differs from lastPullRev', async () => {
+3 -5
View File
@@ -732,13 +732,11 @@ async function reconcileEnvForUnchangedRepo(
/**
* The stub is the agent's only way into TeamAI, so a failure to deploy it is
* not silent. A SessionStart pull runs detached with its output discarded, and
* `log.warn` is muted there, so debug.log keeps the record.
* not silent. A SessionStart pull runs detached with its output discarded;
* `log.warn` also records to debug.log, which keeps the trace there.
*/
function warnStubNotDeployed(scopeLabel: string, e: unknown): void {
const message = `[${scopeLabel}] The built-in teamai skill was not deployed: ${e instanceof Error ? e.message : String(e)}`;
log.warn(message);
log.debug(message);
log.warn(`[${scopeLabel}] The built-in teamai skill was not deployed: ${e instanceof Error ? e.message : String(e)}`);
}
async function pullForScope(
+2 -1
View File
@@ -10,7 +10,7 @@ let stderrMode = false;
// ─── File transport ─────────────────────────────────────
//
// All log.debug() and log.error() calls are persisted to
// All log.debug(), log.warn() and log.error() calls are persisted to
// ~/.teamai/debug.log via synchronous append. This ensures
// hook processes (short-lived, stdout swallowed by Claude Code)
// leave a durable trace for troubleshooting.
@@ -143,6 +143,7 @@ export const log = {
writeInfoLine(`${chalk.green('✔')} ${msg}`);
},
warn(msg: string): void {
writeToFile('WARN', msg);
if (silentMode) return;
writeInfoLine(`${chalk.yellow('⚠')} ${msg}`);
},