fix(statusline): print nothing instead of the bare word codeman

Ported from #416 (discussion #405): a statusline reading just `codeman`
is what a hand-run claude in a managed repo showed, and it reads as a
broken config rather than a footer. Three paths produced it and all
three now yield an empty footer: the exporter's `|| echo codeman`
fallback (now `curl -sfk ... || true`, with -f keeping an HTTP error
body off stdout), the unknown-session answer of POST /api/status-telemetry,
and formatSessionStatusText() with nothing to show. The exporter script
marker moves to V4 so live installs pick the new content up on the next
spawn.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-09-14 15:59:00 +02:00
parent fa1ea8d9fe
commit e46089bc7f
7 changed files with 41 additions and 24 deletions
+9 -2
View File
@@ -1516,10 +1516,17 @@ describe('statusline exporter script (real shell execution)', () => {
expect(result.stdout.trim()).toBe('model: opus | 42% used');
});
it('no-user-statusline branch: falls back to the plain "codeman" marker when curl fails', async () => {
it('no-user-statusline branch: prints NOTHING when curl fails (never a bare brand word)', async () => {
writeFakeCurl(`exit 1`);
const result = await runExporter(baseEnv);
expect(result.stdout.trim()).toBe('codeman');
expect(result.stdout).toBe('');
expect(result.code).toBe(0);
});
it('asks curl to fail on HTTP errors (-f) so an error body never becomes the footer', async () => {
const scriptPath = await resolveStatusLineCliCommand(testDir, true);
expect(readFileSync(scriptPath!, 'utf-8')).toContain('curl -sfk');
expect(readFileSync(scriptPath!, 'utf-8')).not.toContain('echo codeman');
});
it('wrap branch: never blocks a reader-to-EOF on a slow/hung curl (background subshell closes stdin too)', async () => {
+2 -2
View File
@@ -49,10 +49,10 @@ describe('POST /api/status-telemetry', () => {
});
});
it('does not broadcast for an unknown session; returns the brand footer', async () => {
it('does not broadcast for an unknown session; returns an EMPTY footer, never a brand word', async () => {
const res = await post({ sessionId: 'does-not-exist', data: REAL });
expect(res.statusCode).toBe(200);
expect(res.body).toBe('codeman');
expect(res.body).toBe('');
expect(h.ctx.broadcast).not.toHaveBeenCalled();
});
+1 -1
View File
@@ -19,7 +19,7 @@ import { describe, it, expect } from 'vitest';
import { execFileSync } from 'node:child_process';
import { buildSpawnCommand } from '../src/tmux-manager.js';
const EXPORTER_CMD = 'curl -sk -X POST "$CODEMAN_API_URL/api/status-telemetry" --data @- 2>/dev/null || echo codeman';
const EXPORTER_CMD = 'curl -sfk -X POST "$CODEMAN_API_URL/api/status-telemetry" --data @- 2>/dev/null || true';
/** Extract the `--settings <arg>` fragment from a built command and have a
* real shell resolve its quoting, printing the arg back out verbatim. */
+3 -2
View File
@@ -119,8 +119,9 @@ describe('formatSessionStatusText', () => {
expect(formatSessionStatusText({ modelDisplayName: 'Opus 4.8 (1M context)' })).toBe('Opus 4.8 (1M context)');
});
it('falls back to a brand string when there is no data', () => {
expect(formatSessionStatusText(null)).toBe('codeman');
it('prints nothing when there is no data (a bare brand word reads as a broken statusline)', () => {
expect(formatSessionStatusText(null)).toBe('');
expect(formatSessionStatusText({} as never)).toBe('');
});
});