mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 00:19:42 +02:00
fix(watching): tell the page when the badge goes away
Reported from a manual test: a Codex session went on showing the watching badge after its background terminal had finished. The server was right and the page was stale — `Session.watching` changes while the session's status does not, and nothing broadcast it. The label is usually SET on the idle transition, which broadcasts anyway, so the badge always appeared correctly. It CLEARS when the work ends, and a CLI can end background work without taking a turn: codex repaints its background-terminal row away and stays idle, so `_confirmIdle()` concludes without emitting `idle` (that emit is guarded by `wasWorking || isInitialReady`) and no other event fires. Every open page kept drawing a badge the server had already dropped. `_readWatching()` now emits `watchingChanged` when, and only when, the label really changes, and the wiring pushes the session state on it. No new SSE event: the badge reads off the session payload every surface already has. A/B measured on an isolated beta with the page loaded and then left untouched. Without this commit the server dropped the label at t+50s and the page still showed the badge at t+100s; with it, page and server cleared in the same ten-second window. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
8d45b92eba
commit
b13672596f
@@ -245,6 +245,40 @@ describe('Session.watching', () => {
|
||||
expect(session.watching).toBeNull();
|
||||
});
|
||||
|
||||
it('announces the change, because the session status does not move with it', () => {
|
||||
// Measured on codex: a background terminal finishing repaints the row away and the
|
||||
// session is idle before and after, so no other event fires. Without this one the
|
||||
// server drops the label and every open page goes on drawing the badge.
|
||||
vi.useFakeTimers();
|
||||
const screen = { text: WITH_MONITOR };
|
||||
const session = withFakePane(() => screen.text);
|
||||
const changes: (string | null)[] = [];
|
||||
session.on('watchingChanged', () => changes.push(session.watching));
|
||||
|
||||
runAndSettle(session);
|
||||
expect(changes).toEqual(['1 monitor']);
|
||||
|
||||
// A repaint that carries the composer glyph but no chip: the pane went quiet again
|
||||
// without a turn, which is exactly the case the event exists for.
|
||||
screen.text = NOTHING_RUNNING;
|
||||
feed(session, COMPOSER_REPAINT);
|
||||
vi.advanceTimersByTime(IDLE_SILENCE_MS + 2000);
|
||||
expect(changes).toEqual(['1 monitor', null]);
|
||||
expect(session.status).toBe('idle');
|
||||
});
|
||||
|
||||
it('says nothing while the answer stays the same', () => {
|
||||
vi.useFakeTimers();
|
||||
const session = withFakePane(WITH_MONITOR);
|
||||
const changes: (string | null)[] = [];
|
||||
session.on('watchingChanged', () => changes.push(session.watching));
|
||||
|
||||
runAndSettle(session);
|
||||
runAndSettle(session);
|
||||
runAndSettle(session);
|
||||
expect(changes).toEqual(['1 monitor']);
|
||||
});
|
||||
|
||||
it('keeps its last answer when the screen cannot be read', () => {
|
||||
vi.useFakeTimers();
|
||||
const screen: { text: string | null } = { text: WITH_MONITOR };
|
||||
|
||||
Reference in New Issue
Block a user