fix: Show conflict resolution agents in HQ dashboard
getHeadquartersDashboard had no section for active conflict agents, so initiatives with a running conflict-* agent disappeared from all HQ sections. Add resolvingConflicts array to surface them.
This commit is contained in:
@@ -108,6 +108,7 @@ describe('getHeadquartersDashboard', () => {
|
||||
expect(result.pendingReviewInitiatives).toEqual([]);
|
||||
expect(result.pendingReviewPhases).toEqual([]);
|
||||
expect(result.planningInitiatives).toEqual([]);
|
||||
expect(result.resolvingConflicts).toEqual([]);
|
||||
expect(result.blockedPhases).toEqual([]);
|
||||
});
|
||||
|
||||
@@ -291,6 +292,115 @@ describe('getHeadquartersDashboard', () => {
|
||||
expect(item.lastMessage).toBeNull();
|
||||
});
|
||||
|
||||
it('resolvingConflicts — running conflict agent appears', async () => {
|
||||
const agents = new MockAgentManager();
|
||||
const ctx = makeCtx(agents);
|
||||
const initiativeRepo = ctx.initiativeRepository!;
|
||||
const initiative = await initiativeRepo.create({ name: 'Conflicting Init', status: 'active' });
|
||||
|
||||
agents.addAgent({
|
||||
id: 'agent-conflict',
|
||||
name: 'conflict-1234567890',
|
||||
status: 'running',
|
||||
initiativeId: initiative.id,
|
||||
userDismissedAt: null,
|
||||
updatedAt: new Date('2025-06-01T12:00:00Z'),
|
||||
});
|
||||
|
||||
const caller = createCaller(ctx);
|
||||
const result = await caller.getHeadquartersDashboard();
|
||||
|
||||
expect(result.resolvingConflicts).toHaveLength(1);
|
||||
const item = result.resolvingConflicts[0];
|
||||
expect(item.initiativeId).toBe(initiative.id);
|
||||
expect(item.initiativeName).toBe('Conflicting Init');
|
||||
expect(item.agentId).toBe('agent-conflict');
|
||||
expect(item.agentName).toBe('conflict-1234567890');
|
||||
expect(item.agentStatus).toBe('running');
|
||||
});
|
||||
|
||||
it('resolvingConflicts — waiting_for_input conflict agent appears', async () => {
|
||||
const agents = new MockAgentManager();
|
||||
const ctx = makeCtx(agents);
|
||||
const initiativeRepo = ctx.initiativeRepository!;
|
||||
const initiative = await initiativeRepo.create({ name: 'Conflicting Init', status: 'active' });
|
||||
|
||||
agents.addAgent({
|
||||
id: 'agent-conflict',
|
||||
name: 'conflict-1234567890',
|
||||
status: 'waiting_for_input',
|
||||
initiativeId: initiative.id,
|
||||
userDismissedAt: null,
|
||||
updatedAt: new Date('2025-06-01T12:00:00Z'),
|
||||
});
|
||||
|
||||
const caller = createCaller(ctx);
|
||||
const result = await caller.getHeadquartersDashboard();
|
||||
|
||||
expect(result.resolvingConflicts).toHaveLength(1);
|
||||
expect(result.resolvingConflicts[0].agentStatus).toBe('waiting_for_input');
|
||||
});
|
||||
|
||||
it('resolvingConflicts — dismissed conflict agent is excluded', async () => {
|
||||
const agents = new MockAgentManager();
|
||||
const ctx = makeCtx(agents);
|
||||
const initiativeRepo = ctx.initiativeRepository!;
|
||||
const initiative = await initiativeRepo.create({ name: 'Conflicting Init', status: 'active' });
|
||||
|
||||
agents.addAgent({
|
||||
id: 'agent-conflict',
|
||||
name: 'conflict-1234567890',
|
||||
status: 'running',
|
||||
initiativeId: initiative.id,
|
||||
userDismissedAt: new Date(),
|
||||
});
|
||||
|
||||
const caller = createCaller(ctx);
|
||||
const result = await caller.getHeadquartersDashboard();
|
||||
|
||||
expect(result.resolvingConflicts).toEqual([]);
|
||||
});
|
||||
|
||||
it('resolvingConflicts — idle conflict agent is excluded', async () => {
|
||||
const agents = new MockAgentManager();
|
||||
const ctx = makeCtx(agents);
|
||||
const initiativeRepo = ctx.initiativeRepository!;
|
||||
const initiative = await initiativeRepo.create({ name: 'Conflicting Init', status: 'active' });
|
||||
|
||||
agents.addAgent({
|
||||
id: 'agent-conflict',
|
||||
name: 'conflict-1234567890',
|
||||
status: 'idle',
|
||||
initiativeId: initiative.id,
|
||||
userDismissedAt: null,
|
||||
});
|
||||
|
||||
const caller = createCaller(ctx);
|
||||
const result = await caller.getHeadquartersDashboard();
|
||||
|
||||
expect(result.resolvingConflicts).toEqual([]);
|
||||
});
|
||||
|
||||
it('resolvingConflicts — non-conflict agent is excluded', async () => {
|
||||
const agents = new MockAgentManager();
|
||||
const ctx = makeCtx(agents);
|
||||
const initiativeRepo = ctx.initiativeRepository!;
|
||||
const initiative = await initiativeRepo.create({ name: 'Some Init', status: 'active' });
|
||||
|
||||
agents.addAgent({
|
||||
id: 'agent-regular',
|
||||
name: 'regular-agent',
|
||||
status: 'running',
|
||||
initiativeId: initiative.id,
|
||||
userDismissedAt: null,
|
||||
});
|
||||
|
||||
const caller = createCaller(ctx);
|
||||
const result = await caller.getHeadquartersDashboard();
|
||||
|
||||
expect(result.resolvingConflicts).toEqual([]);
|
||||
});
|
||||
|
||||
it('ordering — waitingForInput sorted oldest first', async () => {
|
||||
const agents = new MockAgentManager();
|
||||
const ctx = makeCtx(agents);
|
||||
|
||||
@@ -145,7 +145,40 @@ export function headquartersProcedures(publicProcedure: ProcedureBuilder) {
|
||||
planningInitiatives.sort((a, b) => a.since.localeCompare(b.since));
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Section 4: blockedPhases
|
||||
// Section 4: resolvingConflicts
|
||||
// -----------------------------------------------------------------------
|
||||
const resolvingConflicts: Array<{
|
||||
initiativeId: string;
|
||||
initiativeName: string;
|
||||
agentId: string;
|
||||
agentName: string;
|
||||
agentStatus: string;
|
||||
since: string;
|
||||
}> = [];
|
||||
|
||||
for (const agent of activeAgents) {
|
||||
if (
|
||||
agent.name?.startsWith('conflict-') &&
|
||||
(agent.status === 'running' || agent.status === 'waiting_for_input') &&
|
||||
agent.initiativeId
|
||||
) {
|
||||
const initiative = initiativeMap.get(agent.initiativeId);
|
||||
if (initiative) {
|
||||
resolvingConflicts.push({
|
||||
initiativeId: initiative.id,
|
||||
initiativeName: initiative.name,
|
||||
agentId: agent.id,
|
||||
agentName: agent.name,
|
||||
agentStatus: agent.status,
|
||||
since: agent.updatedAt.toISOString(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
resolvingConflicts.sort((a, b) => a.since.localeCompare(b.since));
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Section 5: blockedPhases
|
||||
// -----------------------------------------------------------------------
|
||||
const blockedPhases: Array<{
|
||||
initiativeId: string;
|
||||
@@ -207,6 +240,7 @@ export function headquartersProcedures(publicProcedure: ProcedureBuilder) {
|
||||
pendingReviewInitiatives,
|
||||
pendingReviewPhases,
|
||||
planningInitiatives,
|
||||
resolvingConflicts,
|
||||
blockedPhases,
|
||||
};
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user