Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | 115x 115x 115x 115x 24x 24x 2x 22x 22x 2x 20x 28x 20x 20x 20x 20x 20x 20x 19x 27x 19x 20x 19x 19x | /**
* ConflictResolutionService
*
* Service responsible for handling merge conflicts by:
* - Creating conflict resolution tasks
* - Updating original task status
* - Notifying agents via messages
* - Emitting appropriate events
*
* This service is used by the CoordinationManager when merge conflicts occur.
*/
import type { EventBus, TaskQueuedEvent } from '../events/index.js';
import type { TaskRepository } from '../db/repositories/task-repository.js';
import type { AgentRepository } from '../db/repositories/agent-repository.js';
import type { MessageRepository } from '../db/repositories/message-repository.js';
// =============================================================================
// ConflictResolutionService Interface (Port)
// =============================================================================
/**
* Service interface for handling merge conflicts.
* This is the PORT - implementations are ADAPTERS.
*/
/**
* Branch context for merge conflicts from the branch hierarchy.
*/
export interface MergeContext {
sourceBranch: string;
targetBranch: string;
}
export interface ConflictResolutionService {
/**
* Handle a merge conflict by creating resolution task and notifying agent.
*
* @param taskId - ID of the task that conflicted
* @param conflicts - List of conflicting file paths
* @param mergeContext - Optional branch context for branch hierarchy merges
*/
handleConflict(taskId: string, conflicts: string[], mergeContext?: MergeContext): Promise<void>;
}
// =============================================================================
// DefaultConflictResolutionService Implementation (Adapter)
// =============================================================================
/**
* Default implementation of ConflictResolutionService.
*
* Creates conflict resolution tasks, updates task statuses, sends messages
* to agents, and emits events when merge conflicts occur.
*/
export class DefaultConflictResolutionService implements ConflictResolutionService {
constructor(
private taskRepository: TaskRepository,
private agentRepository: AgentRepository,
private messageRepository?: MessageRepository,
private eventBus?: EventBus
) {}
/**
* Handle a merge conflict.
* Creates a conflict-resolution task and notifies the agent via message.
*/
async handleConflict(taskId: string, conflicts: string[], mergeContext?: MergeContext): Promise<void> {
// Get original task for context
const originalTask = await this.taskRepository.findById(taskId);
if (!originalTask) {
throw new Error(`Original task not found: ${taskId}`);
}
// Get agent that was working on the task
const agent = await this.agentRepository.findByTaskId(taskId);
if (!agent) {
throw new Error(`No agent found for task: ${taskId}`);
}
// Build conflict description
const descriptionLines = [
'Merge conflicts detected. Resolve conflicts in the following files:',
'',
...conflicts.map((f) => `- ${f}`),
'',
`Original task: ${originalTask.name}`,
'',
];
Iif (mergeContext) {
descriptionLines.push(
`Resolve merge conflicts between branch "${mergeContext.sourceBranch}" and "${mergeContext.targetBranch}".`,
`Run: git merge ${mergeContext.sourceBranch} --no-edit`,
'Resolve all conflicts, then: git add . && git commit',
);
} else {
descriptionLines.push(
'Instructions: Resolve merge conflicts in the listed files, then mark task complete.',
);
}
const conflictDescription = descriptionLines.join('\n');
// Create new conflict-resolution task
const conflictTask = await this.taskRepository.create({
parentTaskId: originalTask.parentTaskId,
phaseId: originalTask.phaseId,
initiativeId: originalTask.initiativeId,
name: `Resolve conflicts: ${originalTask.name}`,
description: conflictDescription,
category: mergeContext ? 'merge' : 'execute',
type: 'auto',
priority: 'high',
status: 'pending',
order: originalTask.order + 1,
});
// Update original task status to blocked
await this.taskRepository.update(taskId, { status: 'blocked' });
// Create message to agent if messageRepository is configured
if (this.messageRepository) {
const messageContent = [
`Merge conflict detected for task: ${originalTask.name}`,
'',
'Conflicting files:',
...conflicts.map((f) => `- ${f}`),
'',
`A new task has been created to resolve these conflicts: ${conflictTask.name}`,
'',
'Please resolve the merge conflicts in the listed files and mark the resolution task as complete.',
].join('\n');
await this.messageRepository.create({
senderType: 'user', // System-generated messages appear as from user
senderId: null,
recipientType: 'agent',
recipientId: agent.id,
type: 'info',
content: messageContent,
requiresResponse: false,
});
}
// Emit TaskQueuedEvent for the new conflict-resolution task
if (this.eventBus) {
const event: TaskQueuedEvent = {
type: 'task:queued',
timestamp: new Date(),
payload: {
taskId: conflictTask.id,
priority: 'high',
dependsOn: [],
},
};
this.eventBus.emit(event);
}
}
} |