fix(statusline): trailing blank line so the input prompt gets breathing room

The statusline's last row butted directly against Claude Code's input prompt with no visual separation. generateStatusline() now returns lines.join('\n') + '\n', so combined with console.log's own trailing newline the rendered output ends in exactly one blank line.

Regenerated both committed .claude/helpers/statusline.cjs copies (root + package) so the drift-guard test stays in lockstep. Two new tests: a source-level pin on the generator (can't silently regress) and a runtime check on the actual rendered bytes (exactly one blank line — not zero, not two).
This commit is contained in:
ruv committed 2026-07-10 16:56:56 -04:00
1 parent 69dab8edb0
commit d3341b0336
4 files changed
+44 -3

No files matched your search

+3 -1
View File
@@ -710,7 +710,9 @@ function generateStatusline() {
lines.push(promoColor + promoRow + c.reset);
}
return lines.join('\n');
// Trailing blank line so Claude Code's input prompt gets breathing room
// instead of butting directly against the last statusline row.
return lines.join('\n') + '\n';
}
// ─── Funnel promo row (ADR-301) ─────────────────────────────────
@@ -710,7 +710,9 @@ function generateStatusline() {
lines.push(promoColor + promoRow + c.reset);
}
return lines.join('\n');
// Trailing blank line so Claude Code's input prompt gets breathing room
// instead of butting directly against the last statusline row.
return lines.join('\n') + '\n';
}
// ─── Funnel promo row (ADR-301) ─────────────────────────────────
@@ -114,3 +114,38 @@ describe('statusline cost display — committed artifact drift guard', () => {
expect(readFileSync(artifact, 'utf-8')).toBe(SCRIPT);
});
});
describe('statusline trailing newline — breathing room before the input prompt', () => {
it('generator source appends a trailing newline after joining lines', () => {
// Source-level pin: a future edit can't silently drop the `+ '\n'` without
// this test noticing, even before anyone runs the script.
expect(SCRIPT).toContain("lines.join('\\n') + '\\n'");
});
it('the rendered statusline output ends with a real newline character', () => {
const dir = mkdtempSync(path.join(tmpdir(), 'ruflo-statusline-nl-'));
const scriptPath = path.join(dir, 'statusline.cjs');
writeFileSync(scriptPath, SCRIPT, 'utf-8');
const payload = JSON.stringify({
model: { display_name: 'Opus 4.8' },
context_window: { used_percentage: 34 },
cost: { total_cost_usd: 1.3, total_duration_ms: 376000 },
});
try {
const out = execFileSync(process.execPath, [scriptPath], {
input: payload,
encoding: 'utf-8',
env: { PATH: '/nonexistent', HOME: dir },
timeout: 15000,
});
// console.log appends its own trailing newline on top of the one this
// fix adds, so the real output ends with the last content line, then
// exactly one blank line — not zero (no breathing room) and not two+
// (console.log double-counted the fix, or a duplicate `+ '\n'` crept in).
expect(out.endsWith('\n\n')).toBe(true);
expect(out.endsWith('\n\n\n')).toBe(false);
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
});
@@ -737,7 +737,9 @@ function generateStatusline() {
lines.push(promoColor + promoRow + c.reset);
}
return lines.join('\\n');
// Trailing blank line so Claude Code's input prompt gets breathing room
// instead of butting directly against the last statusline row.
return lines.join('\\n') + '\\n';
}
// ─── Funnel promo row (ADR-301) ─────────────────────────────────