fix(merge): clear mergeActive + abort wedged session on stale-merge recovery
The prior commit re-enqueued tasks after stale-merge recovery but didn't account for the engine's in-memory `mergeActive` set, which still held the wedged task. `internalEnqueueMerge` silently no-ops when the entry is present, so the re-enqueue had no effect. The recovery callback now also aborts the active merge's signal and disposes its session if the wedged attempt was the currently-active one. This is what unsticks tasks where an AI provider call is hung mid-await and the surrounding `try/finally` never gets a chance to run. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -195,8 +195,28 @@ export class ProjectEngine {
|
||||
// Let the runtime's SelfHealingManager re-enqueue tasks directly into our
|
||||
// auto-merge queue when it clears a stale `merging` status, instead of
|
||||
// relying on the 15s polling sweep to eventually catch them.
|
||||
//
|
||||
// Critically: clear the in-memory `mergeActive` entry before re-enqueueing.
|
||||
// A stale-merge recovery means the prior merge attempt is dead — but its
|
||||
// `try/finally` may never have fired (e.g. an AI provider call is wedged
|
||||
// mid-await), so the entry is still in `mergeActive` and would otherwise
|
||||
// cause `internalEnqueueMerge` to silently no-op.
|
||||
//
|
||||
// Tests substitute a minimal runtime mock that may not implement this hook.
|
||||
this.runtime.setMergeEnqueuer?.((taskId) => this.internalEnqueueMerge(taskId));
|
||||
this.runtime.setMergeEnqueuer?.((taskId) => {
|
||||
// If the wedged attempt was the active one, abort its in-flight signal
|
||||
// and dispose its session so subsequent code paths can release file
|
||||
// handles / child processes promptly.
|
||||
if (this.activeMergeTaskId === taskId) {
|
||||
this.mergeAbortController?.abort();
|
||||
this.mergeAbortController = null;
|
||||
this.activeMergeSession?.dispose();
|
||||
this.activeMergeSession = null;
|
||||
this.activeMergeTaskId = null;
|
||||
}
|
||||
this.mergeActive.delete(taskId);
|
||||
this.internalEnqueueMerge(taskId);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user