diff --git a/src/core/services/checkinService.ts b/src/core/services/checkinService.ts index 6c8c7da..5aab6bc 100644 --- a/src/core/services/checkinService.ts +++ b/src/core/services/checkinService.ts @@ -135,7 +135,15 @@ export function resolvePending( } } - const unread = listMessages(cwd).filter((m) => m.status === 'unread' && isMine(m.to)); + // `unread` UND `delivered`: `delivered` heißt nur "einmal ausgeliefert", nicht + // "gelesen" — erst read/acked schließt eine Nachricht ab. Filterte man hier + // auf `unread`, verschwände jede Nachricht aus dem Rückkanal, sobald sie + // einmal irgendwo aufgetaucht ist (z. B. beim Session-Start), ohne dass der + // Agent sie je beantwortet hat. Real passiert bei einer Architekten-Korrektur + // an kimi: Status `delivered`, im Check-in unsichtbar. + const unread = listMessages(cwd).filter( + (m) => (m.status === 'unread' || m.status === 'delivered') && isMine(m.to), + ); pending.unreadCount = unread.length; pending.messages = unread.slice(-MAX_MESSAGE_PREVIEWS).map((m) => ({ id: m.id, @@ -145,7 +153,7 @@ export function resolvePending( const parts: string[] = []; if (pending.interrupted) parts.push(pending.interrupted.action); - if (pending.unreadCount > 0) parts.push(`${pending.unreadCount} ungelesene Nachricht(en) — agenthub_inbox lesen und antworten.`); + if (pending.unreadCount > 0) parts.push(`${pending.unreadCount} unbeantwortete Nachricht(en) — agenthub_inbox lesen, beantworten und mit agenthub_message quittieren.`); if (pending.answeredAsks.length > 0) parts.push(`Deine Frage(n) ${pending.answeredAsks.map((a) => a.id).join(', ')} sind BEANTWORTET — lies die Antwort, bevor du weiterbaust.`); if (pending.waitingTasks.length > 0) parts.push(`Offen für dich: ${pending.waitingTasks.join(', ')}.`); if (parts.length > 0) pending.note = parts.join(' '); diff --git a/tests/checkinService.test.ts b/tests/checkinService.test.ts index 9cf733d..e790eb3 100644 --- a/tests/checkinService.test.ts +++ b/tests/checkinService.test.ts @@ -3,7 +3,7 @@ import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { createTask, claimTask, reviewTask, reopenTask, cancelTask, assignTask } from '../src/core/services/taskService.js'; -import { createMessage } from '../src/core/services/messageService.js'; +import { createMessage, markMessageDelivered } from '../src/core/services/messageService.js'; import { resolvePending, hasPending } from '../src/core/services/checkinService.js'; import { createAsk, answerAsk } from '../src/core/services/askService.js'; @@ -98,7 +98,7 @@ describe('resolvePending — Nachrichten und Zuweisungen', () => { expect(pending.unreadCount).toBe(1); expect(pending.messages[0]?.from).toBe('claude'); expect(pending.messages[0]?.preview).toContain('Reihenfolge'); - expect(pending.note).toMatch(/ungelesene/i); + expect(pending.note).toMatch(/unbeantwortete/i); }); it('nennt offene, an den Agenten adressierte Tasks', () => { @@ -156,3 +156,17 @@ describe('resolvePending — beantwortete Fragen (Ask-Timeout-Lücke)', () => { expect(resolvePending(cwd, 'kimi').answeredAsks).toHaveLength(0); }); }); + +describe('resolvePending — `delivered` zaehlt weiter', () => { + it('zeigt eine bereits ausgelieferte, aber unbeantwortete Nachricht weiter an', () => { + const msg = createMessage(cwd, { from: 'claude', to: 'kimi', text: 'Korrektur: nimm doch Variante A.' }); + markMessageDelivered(cwd, msg.id); + + const pending = resolvePending(cwd, 'kimi'); + + // `delivered` heisst nur "einmal aufgetaucht". Filterte der Check-in auf + // `unread`, ginge eine Architekten-Korrektur still verloren. + expect(pending.unreadCount).toBe(1); + expect(hasPending(pending)).toBe(true); + }); +});