fix(hub): Check-in adressiert wie der Work-Loop (Titel-Präfix + Handoff)
Der Check-in prüfte nur `assignedTo`, `findAddressedOpenTask` dagegen Titel-Präfix `<name>:`, Handoff-Empfänger UND `assignedTo`. Folge: `agenthub start codex` meldete "AKTUELL: nichts offen", während TSK-0268 mit `codex:`-Präfix offen lag — der Work-Loop hätte sie unmittelbar danach geclaimt. Zwei Wahrheiten über dieselbe Frage. Jetzt nutzt der Check-in dieselbe Adressierungslogik. Tests: 293 → 295. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4be0826a6f
commit
1250359e6d
@ -1,6 +1,7 @@
|
||||
import { listTasks } from './taskService.js';
|
||||
import { listMessages } from './messageService.js';
|
||||
import { listAsks } from './askService.js';
|
||||
import { listHandoffs } from './handoffService.js';
|
||||
import { agentIdentity } from './identityService.js';
|
||||
|
||||
/**
|
||||
@ -108,8 +109,28 @@ export function resolvePending(
|
||||
pending.answeredAsks.push({ id: ask.id, answer: previewOf(ask.answer) });
|
||||
}
|
||||
|
||||
// Adressierung EXAKT wie in findAddressedOpenTask (start.ts): Titel-Präfix
|
||||
// `<name>:`, Handoff-Empfänger ODER assignedTo. Prüfte der Check-in nur
|
||||
// assignedTo, meldete der Session-Start "nichts offen" — und der Work-Loop
|
||||
// claimte unmittelbar danach eine Task, die er über das Titel-Präfix findet.
|
||||
// Zwei Wahrheiten über dieselbe Frage sind genau das, was hier nicht passieren darf.
|
||||
let addressedByHandoff = new Set<string>();
|
||||
try {
|
||||
addressedByHandoff = new Set(
|
||||
listHandoffs(cwd)
|
||||
.filter((h) => h.toAgent && isMine(h.toAgent) && h.taskId)
|
||||
.map((h) => String(h.taskId)),
|
||||
);
|
||||
} catch {
|
||||
// Handoffs nicht lesbar — Präfix/assignedTo tragen weiterhin.
|
||||
}
|
||||
const addressedToMe = (task: { id: string; title?: string; assignedTo?: string }) =>
|
||||
[...names].some((n) => (task.title ?? '').toLowerCase().startsWith(`${n}:`)) ||
|
||||
addressedByHandoff.has(task.id) ||
|
||||
isMine(task.assignedTo);
|
||||
|
||||
for (const task of tasks) {
|
||||
if (task.status === 'open' && isMine(task.assignedTo)) pending.waitingTasks.push(task.id);
|
||||
if (task.status === 'open' && addressedToMe(task)) pending.waitingTasks.push(task.id);
|
||||
else if (task.status === 'review' && isMine(task.claimedBy ?? task.assignedTo)) pending.awaitingReview.push(task.id);
|
||||
}
|
||||
|
||||
|
||||
@ -170,3 +170,21 @@ describe('resolvePending — `delivered` zaehlt weiter', () => {
|
||||
expect(hasPending(pending)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolvePending — Adressierung wie im Work-Loop', () => {
|
||||
it('erkennt eine Task am Titel-Praefix, auch ohne assignedTo', () => {
|
||||
// Genau der Fall, der den Session-Start luegen liess: Task traegt das
|
||||
// Praefix, aber kein assignedTo — der Work-Loop haette sie sofort geclaimt.
|
||||
const task = createTask(cwd, { title: 'codex: Blocker-Redesign', role: 'implementer' });
|
||||
|
||||
const pending = resolvePending(cwd, 'codex');
|
||||
|
||||
expect(pending.waitingTasks).toContain(task.id);
|
||||
expect(hasPending(pending)).toBe(true);
|
||||
});
|
||||
|
||||
it('beansprucht keine fremd adressierte Task', () => {
|
||||
createTask(cwd, { title: 'kimi: nicht meins', role: 'implementer' });
|
||||
expect(resolvePending(cwd, 'codex').waitingTasks).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user