From 609c485fc6d0a0c24a023cd1349ebd6ddbf60315 Mon Sep 17 00:00:00 2001 From: Austin Pickett Date: Mon, 18 May 2026 08:42:33 -0400 Subject: [PATCH] Merge pull request #27971 from NousResearch/austin/fix/goal-statusbar fix(tui): keep /goal verdict out of compact status row --- .../createGatewayEventHandler.test.ts | 42 ++++++++++++++++++- ui-tui/src/app/createGatewayEventHandler.ts | 17 ++++++-- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/ui-tui/src/__tests__/createGatewayEventHandler.test.ts b/ui-tui/src/__tests__/createGatewayEventHandler.test.ts index cd278eecdf9..0c7ec3b06ad 100644 --- a/ui-tui/src/__tests__/createGatewayEventHandler.test.ts +++ b/ui-tui/src/__tests__/createGatewayEventHandler.test.ts @@ -4,7 +4,7 @@ import { createGatewayEventHandler } from '../app/createGatewayEventHandler.js' import { getOverlayState, resetOverlayState } from '../app/overlayStore.js' import { turnController } from '../app/turnController.js' import { getTurnState, resetTurnState } from '../app/turnStore.js' -import { patchUiState, resetUiState } from '../app/uiStore.js' +import { getUiState, patchUiState, resetUiState } from '../app/uiStore.js' import { estimateTokensRough } from '../lib/text.js' import type { Msg } from '../types.js' @@ -132,6 +132,46 @@ describe('createGatewayEventHandler', () => { expect(ctx.system.sys).toHaveBeenCalledWith('compressing 968 messages (~123,400 tok)…') }) + it('keeps goal verdict text in transcript but shows a brief idle status (#goal statusbar)', () => { + const appended: Msg[] = [] + const ctx = buildCtx(appended) + const onEvent = createGatewayEventHandler(ctx) + const verdict = '✓ Goal achieved: long judge reason goes only in transcript, not merged with cwd label.' + + vi.useFakeTimers() + try { + onEvent({ + payload: { kind: 'goal', text: verdict }, + type: 'status.update' + } as any) + + expect(ctx.system.sys).toHaveBeenCalledWith(verdict) + expect(getUiState().status).toBe('✓ goal complete') + + vi.advanceTimersByTime(6001) + expect(getUiState().status).toBe('ready') + } finally { + vi.useRealTimers() + } + }) + + it('maps goal status.update prefixes to short status strings', () => { + const ctx = buildCtx([]) + const onEvent = createGatewayEventHandler(ctx) + + onEvent({ + payload: { kind: 'goal', text: '↻ Continuing toward goal (1/10): reason' }, + type: 'status.update' + } as any) + expect(getUiState().status).toBe('↻ goal continuing') + + onEvent({ + payload: { kind: 'goal', text: '⏸ Goal paused — budget exhausted.' }, + type: 'status.update' + } as any) + expect(getUiState().status).toBe('⏸ goal paused') + }) + it('surfaces self-improvement review summaries as a persistent system line', () => { const appended: Msg[] = [] const ctx = buildCtx(appended) diff --git a/ui-tui/src/app/createGatewayEventHandler.ts b/ui-tui/src/app/createGatewayEventHandler.ts index ca269a131b4..267334bfd72 100644 --- a/ui-tui/src/app/createGatewayEventHandler.ts +++ b/ui-tui/src/app/createGatewayEventHandler.ts @@ -338,14 +338,23 @@ export function createGatewayEventHandler(ctx: GatewayEventHandlerContext): (ev: return } - setStatus(p.text) - - if (p.kind === 'compressing') { + if (p.kind === 'goal') { sys(p.text) + const brief = p.text.startsWith('✓') + ? '✓ goal complete' + : p.text.startsWith('↻') + ? '↻ goal continuing' + : p.text.startsWith('⏸') + ? '⏸ goal paused' + : 'ready' + setStatus(brief) + restoreStatusAfter(6000) return } - if (p.kind === 'goal') { + setStatus(p.text) + + if (p.kind === 'compressing') { sys(p.text) return }