diff --git a/apps/mcp-server/src/tui/components/FlowMap.spec.tsx b/apps/mcp-server/src/tui/components/FlowMap.spec.tsx
index 8cab01c2..4b5ed870 100644
--- a/apps/mcp-server/src/tui/components/FlowMap.spec.tsx
+++ b/apps/mcp-server/src/tui/components/FlowMap.spec.tsx
@@ -143,6 +143,28 @@ describe('tui/components/FlowMap', () => {
expect(frame).toContain(formatElapsed(now - 90_000, now));
});
+ it('should show pulse icon and elapsed label for running agents in medium mode', () => {
+ const now = 1710700000000;
+ const agents = new Map();
+ agents.set(
+ 'a1',
+ createDefaultDashboardNode({
+ id: 'a1',
+ name: 'Architect',
+ stage: 'PLAN',
+ status: 'running',
+ isPrimary: true,
+ startedAt: now - 120_000, // 2 minutes ago
+ }),
+ );
+ const { lastFrame } = render(
+ ,
+ );
+ const frame = lastFrame() ?? '';
+ expect(frame).toContain(pulseIcon(1));
+ expect(frame).toContain(formatElapsed(now - 120_000, now));
+ });
+
it('should NOT show pulse icon when no agents are running', () => {
const now = 1710700000000;
const agents = new Map();
diff --git a/apps/mcp-server/src/tui/components/FocusedAgentPanel.spec.tsx b/apps/mcp-server/src/tui/components/FocusedAgentPanel.spec.tsx
index 2ef5e694..2142c2ee 100644
--- a/apps/mcp-server/src/tui/components/FocusedAgentPanel.spec.tsx
+++ b/apps/mcp-server/src/tui/components/FocusedAgentPanel.spec.tsx
@@ -210,6 +210,30 @@ describe('tui/components/FocusedAgentPanel', () => {
expect(frame).not.toContain('1m 23s');
});
+ it('should show spinner but hide elapsed when tick is provided without now', () => {
+ const runningAgent = createDefaultDashboardNode({
+ id: 'agent-1',
+ name: 'BackendDev',
+ stage: 'ACT',
+ status: 'running',
+ isPrimary: true,
+ progress: 50,
+ startedAt: 1710000000000,
+ });
+ const { lastFrame } = render(
+ ,
+ );
+ const frame = lastFrame() ?? '';
+ expect(frame).toContain('⠋'); // spinner shown
+ expect(frame).not.toMatch(/\d+m \d+s/); // no elapsed time
+ });
+
it('should not show elapsed when startedAt is missing', () => {
const now = 1710000090000;
const { lastFrame } = render(
diff --git a/apps/mcp-server/src/tui/hooks/use-tick.spec.tsx b/apps/mcp-server/src/tui/hooks/use-tick.spec.tsx
index 85ef9cd3..56134191 100644
--- a/apps/mcp-server/src/tui/hooks/use-tick.spec.tsx
+++ b/apps/mcp-server/src/tui/hooks/use-tick.spec.tsx
@@ -54,6 +54,24 @@ describe('tui/hooks/useTick', () => {
expect(lastFrame()).toBe('2');
});
+ it('should reset interval when intervalMs prop changes', () => {
+ const clearIntervalSpy = vi.spyOn(global, 'clearInterval');
+ const { lastFrame, rerender } = render();
+ act(() => {
+ vi.advanceTimersByTime(1000);
+ });
+ expect(lastFrame()).toBe('1');
+
+ rerender();
+ expect(clearIntervalSpy).toHaveBeenCalled();
+
+ act(() => {
+ vi.advanceTimersByTime(500);
+ });
+ expect(lastFrame()).toBe('2');
+ clearIntervalSpy.mockRestore();
+ });
+
it('should cleanup interval on unmount', () => {
const clearIntervalSpy = vi.spyOn(global, 'clearInterval');
const { unmount } = render();