feat(bf-60j): add currentBead field to WorkerInfo
Some checks are pending
CI / test (18.x) (push) Waiting to run
CI / test (20.x) (push) Waiting to run
CI / test (22.x) (push) Waiting to run

Add currentBead field to WorkerInfo in src/types.ts and maintain it in
src/store.ts: set it from bead.claim.succeeded (event.bead) and clear it
(null) on bead.released. Foundation for the worker-card current-bead
display. Update src/store.test.ts to cover claim->set and release->clear.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
jedarden 2026-05-22 15:25:05 -04:00
parent 93b3e9e038
commit e0581f09cb
3 changed files with 69 additions and 7 deletions

View file

@ -231,6 +231,55 @@ describe('InMemoryEventStore', () => {
expect(worker?.beadsCompleted).toBe(0);
});
it('should set currentBead from bead.claim.succeeded event', () => {
store.add(createEvent({ worker: 'w-test', msg: 'bead.claim.succeeded', bead: 'bd-abc123' }));
const worker = store.getWorker('w-test');
expect(worker?.currentBead).toBe('bd-abc123');
});
it('should clear currentBead to null on bead.released event', () => {
// First set currentBead
store.add(createEvent({ worker: 'w-test', msg: 'bead.claim.succeeded', bead: 'bd-abc123' }));
const workerBefore = store.getWorker('w-test');
expect(workerBefore?.currentBead).toBe('bd-abc123');
// Then release the bead
store.add(createEvent({ worker: 'w-test', msg: 'bead.released', bead: 'bd-abc123' }));
const workerAfter = store.getWorker('w-test');
expect(workerAfter?.currentBead).toBeNull();
});
it('should clear currentBead on bead.released regardless of reason', () => {
// Set currentBead
store.add(createEvent({ worker: 'w-test', msg: 'bead.claim.succeeded', bead: 'bd-xyz' }));
// Release with non-success reason
store.add(createEvent({ worker: 'w-test', msg: 'bead.released', reason: 'release_retry', bead: 'bd-xyz' }));
const worker = store.getWorker('w-test');
expect(worker?.currentBead).toBeNull();
});
it('should update currentBead when worker claims another bead', () => {
// Claim first bead
store.add(createEvent({ worker: 'w-test', msg: 'bead.claim.succeeded', bead: 'bd-first' }));
expect(store.getWorker('w-test')?.currentBead).toBe('bd-first');
// Claim second bead
store.add(createEvent({ worker: 'w-test', msg: 'bead.claim.succeeded', bead: 'bd-second' }));
expect(store.getWorker('w-test')?.currentBead).toBe('bd-second');
});
it('should initialize currentBead to null for new workers', () => {
store.add(createEvent({ worker: 'w-newbie', msg: 'worker.started' }));
const worker = store.getWorker('w-newbie');
expect(worker?.currentBead).toBeNull();
});
it('should track firstSeen timestamp', () => {
const earlyTs = 1000;
const lateTs = 5000;

View file

@ -622,6 +622,7 @@ export class InMemoryEventStore implements EventStore {
activeFiles: [],
hasCollision: false,
activeBead: event.bead,
currentBead: null,
activeDirectories: [],
collisionTypes: [],
eventCount: 1,
@ -687,14 +688,18 @@ export class InMemoryEventStore implements EventStore {
worker.activeDirectories = [];
worker.activeBead = undefined;
}
} else if (needleEvent === 'bead.released' && event['reason'] === 'release_success') {
worker.status = 'idle';
if (event.bead) {
worker.beadsCompleted++;
} else if (needleEvent === 'bead.released') {
// Clear currentBead on any bead.released event (regardless of reason)
worker.currentBead = null;
if (event['reason'] === 'release_success') {
worker.status = 'idle';
if (event.bead) {
worker.beadsCompleted++;
}
worker.activeFiles = [];
worker.activeDirectories = [];
worker.activeBead = undefined;
}
worker.activeFiles = [];
worker.activeDirectories = [];
worker.activeBead = undefined;
} else if (
needleEvent === 'worker.started' ||
needleEvent === 'bead.claimed' ||
@ -705,6 +710,11 @@ export class InMemoryEventStore implements EventStore {
}
}
// Set currentBead from bead.claim.succeeded event
if (needleEvent === 'bead.claim.succeeded' && event.bead) {
worker.currentBead = event.bead;
}
// Update last event
worker.lastEvent = event;

View file

@ -551,6 +551,9 @@ export interface WorkerInfo {
/** Current bead/task being worked on */
activeBead?: string;
/** Current bead from bead.claim.succeeded, cleared on bead.released */
currentBead: string | null;
/** Directories this worker is active in */
activeDirectories: string[];