fix: Prevent conflict resolution agent from destroying initiative branch
spawnConflictResolutionAgent was passing the initiative branch as branchName, causing SimpleGitWorktreeManager.create() to force-reset it to the target branch. Now spawns on a unique temp branch based off the initiative branch, with the agent using git update-ref to advance the initiative branch after resolving conflicts. Also fixes stale diff/commits cache after resolution.
This commit is contained in:
@@ -18,7 +18,7 @@ export function buildConflictResolutionPrompt(
|
|||||||
const conflictList = conflicts.map(f => `- \`${f}\``).join('\n');
|
const conflictList = conflicts.map(f => `- \`${f}\``).join('\n');
|
||||||
|
|
||||||
return `<role>
|
return `<role>
|
||||||
You are a Conflict Resolution agent. Your job is to merge \`${targetBranch}\` into \`${sourceBranch}\` and resolve all merge conflicts so the initiative branch is up to date with the target branch.
|
You are a Conflict Resolution agent. Your job is to merge \`${targetBranch}\` into the initiative branch \`${sourceBranch}\` and resolve all merge conflicts. You are working on a temporary branch created from \`${sourceBranch}\`. After resolving conflicts and committing, you must advance the initiative branch pointer using \`git update-ref\`.
|
||||||
</role>
|
</role>
|
||||||
|
|
||||||
<conflict_details>
|
<conflict_details>
|
||||||
@@ -52,13 +52,16 @@ Follow these steps in order:
|
|||||||
|
|
||||||
6. **Commit**: Stage resolved files with \`git add <file>\` (never \`git add .\`), then \`git commit --no-edit\` to complete the merge commit.
|
6. **Commit**: Stage resolved files with \`git add <file>\` (never \`git add .\`), then \`git commit --no-edit\` to complete the merge commit.
|
||||||
|
|
||||||
7. **Signal done**: Write signal.json with status "done".
|
7. **Update initiative branch**: Run \`git update-ref refs/heads/${sourceBranch} HEAD\` to advance the initiative branch to include the merge result. This is necessary because you are working on a temporary branch — this command propagates the merge commit to the actual initiative branch.
|
||||||
|
|
||||||
|
8. **Signal done**: Write signal.json with status "done".
|
||||||
</resolution_protocol>
|
</resolution_protocol>
|
||||||
${GIT_WORKFLOW}
|
${GIT_WORKFLOW}
|
||||||
${CONTEXT_MANAGEMENT}
|
${CONTEXT_MANAGEMENT}
|
||||||
|
|
||||||
<important>
|
<important>
|
||||||
- You are merging ${targetBranch} INTO ${sourceBranch} — bringing the initiative branch up to date, NOT the other way around.
|
- You are on a temporary branch created from ${sourceBranch}. You are merging ${targetBranch} INTO this branch — bringing it up to date, NOT the other way around.
|
||||||
|
- After committing the merge, you MUST run \`git update-ref refs/heads/${sourceBranch} HEAD\` to advance the initiative branch pointer. Without this step, the initiative branch will not reflect the merge.
|
||||||
- Do NOT force-push or rebase. A merge commit is the correct approach.
|
- Do NOT force-push or rebase. A merge commit is the correct approach.
|
||||||
- If tests fail after resolution, fix the code — don't skip tests.
|
- If tests fail after resolution, fix the code — don't skip tests.
|
||||||
- If a conflict is genuinely ambiguous (e.g., both sides rewrote the same function differently), signal "questions" with the specific ambiguity and your proposed resolution.
|
- If a conflict is genuinely ambiguous (e.g., both sides rewrote the same function differently), signal "questions" with the specific ambiguity and your proposed resolution.
|
||||||
|
|||||||
@@ -459,7 +459,10 @@ export function initiativeProcedures(publicProcedure: ProcedureBuilder) {
|
|||||||
status: 'in_progress',
|
status: 'in_progress',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Spawn agent
|
// Spawn agent on a unique temp branch based off the initiative branch.
|
||||||
|
// Using initiative.branch directly as branchName would cause SimpleGitWorktreeManager.create()
|
||||||
|
// to run `git branch -f <branch> <base>`, force-resetting the initiative branch.
|
||||||
|
const tempBranch = `${initiative.branch}-conflict-${Date.now()}`;
|
||||||
const prompt = buildConflictResolutionPrompt(initiative.branch, targetBranch, conflicts);
|
const prompt = buildConflictResolutionPrompt(initiative.branch, targetBranch, conflicts);
|
||||||
return agentManager.spawn({
|
return agentManager.spawn({
|
||||||
name: `conflict-${Date.now()}`,
|
name: `conflict-${Date.now()}`,
|
||||||
@@ -468,8 +471,8 @@ export function initiativeProcedures(publicProcedure: ProcedureBuilder) {
|
|||||||
mode: 'execute',
|
mode: 'execute',
|
||||||
provider: input.provider,
|
provider: input.provider,
|
||||||
initiativeId: input.initiativeId,
|
initiativeId: input.initiativeId,
|
||||||
baseBranch: targetBranch,
|
baseBranch: initiative.branch,
|
||||||
branchName: initiative.branch,
|
branchName: tempBranch,
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -68,8 +68,10 @@ export function InitiativeReview({ initiativeId, onCompleted }: InitiativeReview
|
|||||||
// When agent transitions from running/waiting to idle (completed)
|
// When agent transitions from running/waiting to idle (completed)
|
||||||
if (prev && ['running', 'waiting_for_input'].includes(prev) && conflictAgentStatus === 'idle') {
|
if (prev && ['running', 'waiting_for_input'].includes(prev) && conflictAgentStatus === 'idle') {
|
||||||
void mergeabilityQuery.refetch();
|
void mergeabilityQuery.refetch();
|
||||||
|
void diffQuery.refetch();
|
||||||
|
void commitsQuery.refetch();
|
||||||
}
|
}
|
||||||
}, [conflictAgentStatus, mergeabilityQuery]);
|
}, [conflictAgentStatus, mergeabilityQuery, diffQuery, commitsQuery]);
|
||||||
|
|
||||||
// Preview state
|
// Preview state
|
||||||
const projectsQuery = trpc.getInitiativeProjects.useQuery({ initiativeId });
|
const projectsQuery = trpc.getInitiativeProjects.useQuery({ initiativeId });
|
||||||
@@ -266,7 +268,11 @@ export function InitiativeReview({ initiativeId, onCompleted }: InitiativeReview
|
|||||||
<ConflictResolutionPanel
|
<ConflictResolutionPanel
|
||||||
initiativeId={initiativeId}
|
initiativeId={initiativeId}
|
||||||
conflicts={mergeability.conflictFiles}
|
conflicts={mergeability.conflictFiles}
|
||||||
onResolved={() => mergeabilityQuery.refetch()}
|
onResolved={() => {
|
||||||
|
void mergeabilityQuery.refetch();
|
||||||
|
void diffQuery.refetch();
|
||||||
|
void commitsQuery.refetch();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user