fix: handle multiple tabs requesting permission
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 55s
CI / Lint & Test (pull_request) Successful in 14m17s
CI / Build Linux (pull_request) Successful in 16m46s
CI / Build Windows (cross-compile) (pull_request) Successful in 26m59s

This commit is contained in:
2026-01-21 14:51:45 -08:00
parent 6567493e57
commit b5893afd3b
3 changed files with 71 additions and 18 deletions
+4 -2
View File
@@ -47,6 +47,8 @@ export const claudeStore = {
getConversationHistory: conversationsStore.getConversationHistory,
requestPermission: conversationsStore.requestPermission,
clearPermission: conversationsStore.clearPermission,
requestPermissionForConversation: conversationsStore.requestPermissionForConversation,
clearPermissionForConversation: conversationsStore.clearPermissionForConversation,
grantTool: conversationsStore.grantTool,
revokeAllTools: conversationsStore.revokeAllTools,
isToolGranted: conversationsStore.isToolGranted,
@@ -83,8 +85,8 @@ export const claudeStore = {
};
export const hasPermissionPending = derived(
claudeStore.pendingPermission,
($permission) => $permission !== null
claudeStore.activeConversation,
($conversation) => $conversation?.pendingPermission !== null
);
// Derived store to check if Claude is currently processing (can be interrupted)
+52 -3
View File
@@ -14,6 +14,7 @@ export interface Conversation {
characterState: CharacterState;
isProcessing: boolean;
grantedTools: Set<string>;
pendingPermission: PermissionRequest | null;
createdAt: Date;
lastActivityAt: Date;
}
@@ -21,7 +22,6 @@ export interface Conversation {
function createConversationsStore() {
const conversations = writable<Map<string, Conversation>>(new Map());
const activeConversationId = writable<string | null>(null);
const pendingPermission = writable<PermissionRequest | null>(null);
const pendingRetryMessage = writable<string | null>(null);
let conversationCounter = 0;
@@ -47,6 +47,7 @@ function createConversationsStore() {
characterState: "idle",
isProcessing: false,
grantedTools: new Set(),
pendingPermission: null,
createdAt: new Date(),
lastActivityAt: new Date(),
};
@@ -93,6 +94,10 @@ function createConversationsStore() {
activeConversation,
($conv) => $conv?.grantedTools || new Set<string>()
);
const pendingPermission = derived(
activeConversation,
($conv) => $conv?.pendingPermission || null
);
return {
// Expose derived stores for compatibility
@@ -148,8 +153,52 @@ function createConversationsStore() {
return convs;
});
},
requestPermission: (request: PermissionRequest) => pendingPermission.set(request),
clearPermission: () => pendingPermission.set(null),
requestPermission: (request: PermissionRequest) => {
const activeId = get(activeConversationId);
if (!activeId) return;
conversations.update((convs) => {
const conv = convs.get(activeId);
if (conv) {
conv.pendingPermission = request;
conv.lastActivityAt = new Date();
}
return convs;
});
},
clearPermission: () => {
const activeId = get(activeConversationId);
if (!activeId) return;
conversations.update((convs) => {
const conv = convs.get(activeId);
if (conv) {
conv.pendingPermission = null;
conv.lastActivityAt = new Date();
}
return convs;
});
},
requestPermissionForConversation: (conversationId: string, request: PermissionRequest) => {
conversations.update((convs) => {
const conv = convs.get(conversationId);
if (conv) {
conv.pendingPermission = request;
conv.lastActivityAt = new Date();
}
return convs;
});
},
clearPermissionForConversation: (conversationId: string) => {
conversations.update((convs) => {
const conv = convs.get(conversationId);
if (conv) {
conv.pendingPermission = null;
conv.lastActivityAt = new Date();
}
return convs;
});
},
setPendingRetryMessage: (message: string | null) => pendingRetryMessage.set(message),
// Conversation management
+15 -13
View File
@@ -292,25 +292,27 @@ export async function initializeTauriListeners() {
const permissionUnlisten = await listen<PermissionPromptEvent>("claude:permission", (event) => {
const { id, tool_name, tool_input, description, conversation_id } = event.payload;
// Only process permission requests for the active conversation
const activeConversationId = get(claudeStore.activeConversationId);
if (conversation_id === activeConversationId) {
// Store permission request for the specific conversation
if (conversation_id) {
claudeStore.requestPermissionForConversation(conversation_id, {
id,
tool: tool_name,
description,
input: tool_input,
});
claudeStore.addLineToConversation(
conversation_id,
"system",
`Permission requested for: ${tool_name}`
);
} else {
// Fallback to active conversation if no conversation_id
claudeStore.requestPermission({
id,
tool: tool_name,
description,
input: tool_input,
});
}
// Always store the permission message to the correct conversation
if (conversation_id) {
claudeStore.addLineToConversation(
conversation_id,
"system",
`Permission requested for: ${tool_name}`
);
} else if (conversation_id === activeConversationId) {
claudeStore.addLine("system", `Permission requested for: ${tool_name}`);
}
});