diff --git a/src/lib/tauri.ts b/src/lib/tauri.ts index 1d5d767..828cae6 100644 --- a/src/lib/tauri.ts +++ b/src/lib/tauri.ts @@ -29,6 +29,7 @@ interface StateChangePayload { } const connectedConversations = new Set(); +const greetingPendingConversations = new Set(); let unlisteners: Array<() => void> = []; let skipNextGreeting = false; @@ -55,17 +56,17 @@ function generateGreetingPrompt(): string { return `[System: A new session has started. It's currently ${timeOfDay}. Please greet the user warmly and briefly. Keep it short - just 1-2 sentences.]`; } -async function sendGreeting(conversationId: string) { +async function sendGreeting(conversationId: string): Promise { // Check if we should skip this greeting if (skipNextGreeting) { skipNextGreeting = false; // Reset the flag - return; + return false; } const config = configStore.getConfig(); if (!config.greeting_enabled) { - return; + return false; } const greetingPrompt = config.greeting_custom_prompt?.trim() || generateGreetingPrompt(); @@ -81,10 +82,12 @@ async function sendGreeting(conversationId: string) { conversationId, message: greetingPrompt, }); + return true; } catch (error) { console.error("Failed to send greeting:", error); claudeStore.addLineToConversation(conversationId, "error", `Failed to send greeting: ${error}`); characterState.setTemporaryState("error", 3000); + return false; } } @@ -118,6 +121,7 @@ interface WorkingDirectoryPayload { export async function cleanupConversationTracking(conversationId: string) { connectedConversations.delete(conversationId); + greetingPendingConversations.delete(conversationId); // Clean up any temp files associated with this conversation try { @@ -173,7 +177,24 @@ export async function initializeTauriListeners() { if (!connectedConversations.has(targetConversationId)) { connectedConversations.add(targetConversationId); resetSessionStats(); // Reset session stats on new connection - await sendGreeting(targetConversationId); + + // Immediately hold the tab at yellow while we wait for the greeting response. + // This avoids a brief green flash before the greeting is even sent. + greetingPendingConversations.add(targetConversationId); + claudeStore.setConnectionStatusForConversation( + targetConversationId, + "connecting" as ConnectionStatus + ); + + const greetingSent = await sendGreeting(targetConversationId); + if (!greetingSent) { + // Greeting was disabled or failed — flip straight to connected. + greetingPendingConversations.delete(targetConversationId); + claudeStore.setConnectionStatusForConversation( + targetConversationId, + "connected" as ConnectionStatus + ); + } } } } else if (status === "disconnected") { @@ -191,6 +212,7 @@ export async function initializeTauriListeners() { // Only remove from connected set if we're not about to reconnect if (!skipNextGreeting && targetConversationId) { connectedConversations.delete(targetConversationId); + greetingPendingConversations.delete(targetConversationId); } // Don't add system message if we're about to reconnect @@ -205,6 +227,14 @@ export async function initializeTauriListeners() { todos.clear(); } + // Update the tab's connection status on real disconnects + if (!skipNextGreeting && targetConversationId) { + claudeStore.setConnectionStatusForConversation( + targetConversationId, + "disconnected" as ConnectionStatus + ); + } + // Update character state for this conversation if (targetConversationId) { claudeStore.setCharacterStateForConversation(targetConversationId, "idle"); @@ -214,6 +244,7 @@ export async function initializeTauriListeners() { if (targetConversationId) { connectedConversations.delete(targetConversationId); + greetingPendingConversations.delete(targetConversationId); claudeStore.addLineToConversation(targetConversationId, "error", "Connection error"); } @@ -275,6 +306,19 @@ export async function initializeTauriListeners() { } : undefined; + // Flip to connected when first assistant message arrives after greeting + if ( + conversation_id && + line_type === "assistant" && + greetingPendingConversations.has(conversation_id) + ) { + greetingPendingConversations.delete(conversation_id); + claudeStore.setConnectionStatusForConversation( + conversation_id, + "connected" as ConnectionStatus + ); + } + // Always store the output to the correct conversation if (conversation_id) { claudeStore.addLineToConversation(