From b4121696bbd68cc9bc56d1c91e8baa86b9fe6bbb Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Wed, 18 Feb 2026 19:56:42 +0000 Subject: [PATCH] fix(ui): track worktree context for question replies Store the originating worktree slug when questions are enqueued and use the stored worktree client when replying/rejecting from the global permission center. This ensures question responses are sent through the correct worktree, matching the behavior already implemented for permissions. --- packages/ui/src/stores/instances.ts | 32 +++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/stores/instances.ts b/packages/ui/src/stores/instances.ts index 66ca1f38..20c63443 100644 --- a/packages/ui/src/stores/instances.ts +++ b/packages/ui/src/stores/instances.ts @@ -52,6 +52,8 @@ const permissionSessionCounts = new Map>() const permissionWorktreeSlugByInstance = new Map>() const [questionQueues, setQuestionQueues] = createSignal>(new Map()) +// Track which worktree a question was enqueued under (by question request id). +const questionWorktreeSlugByInstance = new Map>() const [activeQuestionId, setActiveQuestionId] = createSignal>(new Map()) const questionSessionCounts = new Map>() const questionEnqueuedAt = new Map() @@ -877,6 +879,16 @@ function addQuestionToQueue(instanceId: string, request: QuestionRequest): void if (sessionId) { incrementQuestionSessionPendingCount(instanceId, sessionId) setSessionPendingQuestion(instanceId, sessionId, true) + + // Record the worktree slug at the time the question is enqueued. + // This is used to respond in the same worktree context even from the global permission center. + const slug = getWorktreeSlugForSession(instanceId, sessionId) + let byQuestionId = questionWorktreeSlugByInstance.get(instanceId) + if (!byQuestionId) { + byQuestionId = new Map() + questionWorktreeSlugByInstance.set(instanceId, byQuestionId) + } + byQuestionId.set(request.id, slug) } } @@ -897,6 +909,7 @@ function removeQuestionFromQueue(instanceId: string, requestId: string): void { }) questionEnqueuedAt.delete(requestId) + questionWorktreeSlugByInstance.get(instanceId)?.delete(requestId) recomputeActiveInterruption(instanceId) if (removedSessionId) { @@ -909,6 +922,7 @@ function clearQuestionQueue(instanceId: string): void { for (const request of getQuestionQueue(instanceId)) { questionEnqueuedAt.delete(request.id) } + questionWorktreeSlugByInstance.delete(instanceId) setQuestionQueues((prev) => { const next = new Map(prev) @@ -934,7 +948,7 @@ function setActiveQuestionIdForInstance(instanceId: string, requestId: string): async function sendQuestionReply( instanceId: string, - _sessionId: string, + sessionId: string, requestId: string, answers: string[][], ): Promise { @@ -944,8 +958,13 @@ async function sendQuestionReply( } try { + const stored = questionWorktreeSlugByInstance.get(instanceId)?.get(requestId) + const fallback = sessionId ? getWorktreeSlugForSession(instanceId, sessionId) : "root" + const worktreeSlug = stored ?? fallback + const client = getOrCreateWorktreeClient(instanceId, worktreeSlug) + await requestData( - instance.client.question.reply({ + client.question.reply({ requestID: requestId, answers, }), @@ -959,15 +978,20 @@ async function sendQuestionReply( } } -async function sendQuestionReject(instanceId: string, _sessionId: string, requestId: string): Promise { +async function sendQuestionReject(instanceId: string, sessionId: string, requestId: string): Promise { const instance = instances().get(instanceId) if (!instance?.client) { throw new Error("Instance not ready") } try { + const stored = questionWorktreeSlugByInstance.get(instanceId)?.get(requestId) + const fallback = sessionId ? getWorktreeSlugForSession(instanceId, sessionId) : "root" + const worktreeSlug = stored ?? fallback + const client = getOrCreateWorktreeClient(instanceId, worktreeSlug) + await requestData( - instance.client.question.reject({ + client.question.reject({ requestID: requestId, }), "question.reject",