You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Story 4.3] Serialize approval dialogs for parallel tools #377
cline.ask() writes to clineMessages and waits for a response. If two parallel tools both call ask() concurrently, their writes interleave and produce broken UI state — the second approval prompt would overwrite the first before it's answered. This story adds a write-through promise chain to ask() so concurrent approval requests are serialized transparently.
Developer Notes
In src/core/task/Task.ts:
Add private approvalQueue = pLimit(1) — p-limit is already in deps at ^6.2.0. Using pLimit(1) instead of a hand-rolled promise chain provides better error isolation — a rejected promise in a raw chain breaks the queue unless errors are explicitly caught, whereas p-limit handles this correctly.
Wrap ask() so concurrent calls serialize: return this.approvalQueue(() => actualAsk(...)).
Non-approval paths (auto-approved tools that never call ask()) are unaffected.
Abort drain behavior: When abortTask(true) fires while approvals are queued, pending approvals resolve with denial (not rejection) — producing valid tool_denied results. The queue settles cleanly with no unhandled rejections.
Two parallel tools both requiring approval: second prompt never appears before first resolves. Use controlled promises for ask() mock.
A third tool with auto-approval runs without waiting for the approval queue.
Abort drain: trigger abortTask(true) while two approvals are queued → both resolve with denial → userMessageContent has valid tool_denied results for both with no unhandled rejections.
Acceptance Criteria
No concurrent ask() calls produce overlapping UI state.
Sequential tool execution (flag off) is unaffected.
Abort during queued approvals produces valid results — no unhandled rejections, no missing tool_result entries.
Cross-linking #1308: serializing approval prompts is necessary but should also preserve this invariant: only explicit approval events resolve approval. Queued free-form messages are feedback (messageResponse), not implicit approve/deny actions. This should remain true when approvals are queued under parallel dispatch.
Coordination note for #1223: queued user input can currently be dequeued and lost when finishTask is auto-approved, even with parallel execution disabled. The #1223 fix should establish user-input-over-auto-approval precedence plus non-destructive claim/ack queue handling. This story's serialized approval path should reuse that resolution policy rather than introducing a second queue/approval ordering rule.
Activity
zoomote commentedon Aug 21, 2026
Cross-linking #1308: serializing approval prompts is necessary but should also preserve this invariant: only explicit approval events resolve approval. Queued free-form messages are feedback (
messageResponse), not implicit approve/deny actions. This should remain true when approvals are queued under parallel dispatch.zoomote commentedon Aug 21, 2026
Coordination note for #1223: queued user input can currently be dequeued and lost when
finishTaskis auto-approved, even with parallel execution disabled. The #1223 fix should establish user-input-over-auto-approval precedence plus non-destructive claim/ack queue handling. This story's serialized approval path should reuse that resolution policy rather than introducing a second queue/approval ordering rule.