centralized ask logic
This commit is contained in:
		
							parent
							
								
									8402e7d296
								
							
						
					
					
						commit
						c948d4ed08
					
				@ -22,11 +22,6 @@ async function sendMessage(userPrompt) {
 | 
			
		||||
        console.warn('[AskService] Cannot process empty message');
 | 
			
		||||
        return { success: false, error: 'Empty message' };
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    const askWindow = windowPool.get('ask');
 | 
			
		||||
    if (askWindow && !askWindow.isDestroyed()) {
 | 
			
		||||
        askWindow.webContents.send('hide-text-input');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let sessionId; 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -193,8 +193,6 @@ class ListenService {
 | 
			
		||||
            this.currentSessionId = null;
 | 
			
		||||
            this.summaryService.resetConversationHistory();
 | 
			
		||||
 | 
			
		||||
            this.sendToRenderer('session-did-close');
 | 
			
		||||
 | 
			
		||||
            console.log('Listen service session closed.');
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
 | 
			
		||||
@ -729,17 +729,13 @@ export class AskView extends LitElement {
 | 
			
		||||
        this.handleStreamChunk = this.handleStreamChunk.bind(this);
 | 
			
		||||
        this.handleStreamEnd = this.handleStreamEnd.bind(this);
 | 
			
		||||
        this.handleSendText = this.handleSendText.bind(this);
 | 
			
		||||
        this.handleGlobalSendRequest = this.handleGlobalSendRequest.bind(this);
 | 
			
		||||
        this.handleTextKeydown = this.handleTextKeydown.bind(this);
 | 
			
		||||
        this.closeResponsePanel = this.closeResponsePanel.bind(this);
 | 
			
		||||
        this.handleCopy = this.handleCopy.bind(this);
 | 
			
		||||
        this.clearResponseContent = this.clearResponseContent.bind(this);
 | 
			
		||||
        this.processAssistantQuestion = this.processAssistantQuestion.bind(this);
 | 
			
		||||
        this.handleEscKey = this.handleEscKey.bind(this);
 | 
			
		||||
        this.handleDocumentClick = this.handleDocumentClick.bind(this);
 | 
			
		||||
        this.handleWindowBlur = this.handleWindowBlur.bind(this);
 | 
			
		||||
 | 
			
		||||
        this.handleScroll = this.handleScroll.bind(this);
 | 
			
		||||
        this.handleCloseAskWindow = this.handleCloseAskWindow.bind(this);
 | 
			
		||||
        this.handleCloseIfNoContent = this.handleCloseIfNoContent.bind(this);
 | 
			
		||||
 | 
			
		||||
        this.loadLibraries();
 | 
			
		||||
 | 
			
		||||
@ -747,6 +743,94 @@ export class AskView extends LitElement {
 | 
			
		||||
        this.isThrottled = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connectedCallback() {
 | 
			
		||||
        super.connectedCallback();
 | 
			
		||||
 | 
			
		||||
        console.log('📱 AskView connectedCallback - IPC 이벤트 리스너 설정');
 | 
			
		||||
 | 
			
		||||
        document.addEventListener('keydown', this.handleEscKey);
 | 
			
		||||
 | 
			
		||||
        this.resizeObserver = new ResizeObserver(entries => {
 | 
			
		||||
            for (const entry of entries) {
 | 
			
		||||
                const needed = entry.contentRect.height;
 | 
			
		||||
                const current = window.innerHeight;
 | 
			
		||||
 | 
			
		||||
                if (needed > current - 4) {
 | 
			
		||||
                    this.requestWindowResize(Math.ceil(needed));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const container = this.shadowRoot?.querySelector('.ask-container');
 | 
			
		||||
        if (container) this.resizeObserver.observe(container);
 | 
			
		||||
 | 
			
		||||
        this.handleQuestionFromAssistant = (event, question) => {
 | 
			
		||||
            console.log('📨 AskView: Received question from ListenView:', question);
 | 
			
		||||
            this.handleSendText(null, question);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
            const { ipcRenderer } = window.require('electron');
 | 
			
		||||
            ipcRenderer.on('ask:sendQuestionToRenderer', this.handleQuestionFromAssistant);
 | 
			
		||||
            ipcRenderer.on('hide-text-input', () => {
 | 
			
		||||
                console.log('📤 Hide text input signal received');
 | 
			
		||||
                this.showTextInput = false;
 | 
			
		||||
                this.requestUpdate();
 | 
			
		||||
            });
 | 
			
		||||
            ipcRenderer.on('ask:showTextInput', () => {
 | 
			
		||||
                console.log('📤 Show text input signal received');
 | 
			
		||||
                if (!this.showTextInput) {
 | 
			
		||||
                    this.showTextInput = true;
 | 
			
		||||
                    this.requestUpdate();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            ipcRenderer.on('ask-response-chunk', this.handleStreamChunk);
 | 
			
		||||
            ipcRenderer.on('ask-response-stream-end', this.handleStreamEnd);
 | 
			
		||||
 | 
			
		||||
            ipcRenderer.on('scroll-response-up', () => this.handleScroll('up'));
 | 
			
		||||
            ipcRenderer.on('scroll-response-down', () => this.handleScroll('down'));
 | 
			
		||||
            console.log('✅ AskView: IPC 이벤트 리스너 등록 완료');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    disconnectedCallback() {
 | 
			
		||||
        super.disconnectedCallback();
 | 
			
		||||
        this.resizeObserver?.disconnect();
 | 
			
		||||
 | 
			
		||||
        console.log('📱 AskView disconnectedCallback - IPC 이벤트 리스너 제거');
 | 
			
		||||
 | 
			
		||||
        document.removeEventListener('keydown', this.handleEscKey);
 | 
			
		||||
 | 
			
		||||
        if (this.copyTimeout) {
 | 
			
		||||
            clearTimeout(this.copyTimeout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.headerAnimationTimeout) {
 | 
			
		||||
            clearTimeout(this.headerAnimationTimeout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.streamingTimeout) {
 | 
			
		||||
            clearTimeout(this.streamingTimeout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Object.values(this.lineCopyTimeouts).forEach(timeout => clearTimeout(timeout));
 | 
			
		||||
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
            const { ipcRenderer } = window.require('electron');
 | 
			
		||||
            ipcRenderer.removeListener('hide-text-input', () => { });
 | 
			
		||||
            ipcRenderer.removeListener('ask:showTextInput', () => { });
 | 
			
		||||
 | 
			
		||||
            ipcRenderer.removeListener('ask-response-chunk', this.handleStreamChunk);
 | 
			
		||||
            ipcRenderer.removeListener('ask-response-stream-end', this.handleStreamEnd);
 | 
			
		||||
 | 
			
		||||
            ipcRenderer.removeListener('scroll-response-up', () => this.handleScroll('up'));
 | 
			
		||||
            ipcRenderer.removeListener('scroll-response-down', () => this.handleScroll('down'));
 | 
			
		||||
            console.log('✅ AskView: IPC 이벤트 리스너 제거 완료');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    async loadLibraries() {
 | 
			
		||||
        try {
 | 
			
		||||
            if (!window.marked) {
 | 
			
		||||
@ -803,38 +887,49 @@ export class AskView extends LitElement {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleDocumentClick(e) {
 | 
			
		||||
    handleCloseAskWindow() {
 | 
			
		||||
        this.clearResponseContent();
 | 
			
		||||
        ipcRenderer.invoke('ask:closeAskWindow');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleCloseIfNoContent() {
 | 
			
		||||
        if (!this.currentResponse && !this.isLoading && !this.isStreaming) {
 | 
			
		||||
            const askContainer = this.shadowRoot?.querySelector('.ask-container');
 | 
			
		||||
            if (askContainer && !e.composedPath().includes(askContainer)) {
 | 
			
		||||
                this.closeIfNoContent();
 | 
			
		||||
            }
 | 
			
		||||
            this.handleCloseAskWindow();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleEscKey(e) {
 | 
			
		||||
        if (e.key === 'Escape') {
 | 
			
		||||
            e.preventDefault();
 | 
			
		||||
            this.closeResponsePanel();
 | 
			
		||||
            this.handleCloseIfNoContent();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleWindowBlur() {
 | 
			
		||||
        if (!this.currentResponse && !this.isLoading && !this.isStreaming) {
 | 
			
		||||
            // If there's no active content, ask the main process to close this window.
 | 
			
		||||
            if (window.require) {
 | 
			
		||||
                const { ipcRenderer } = window.require('electron');
 | 
			
		||||
                ipcRenderer.invoke('close-ask-window-if-empty');
 | 
			
		||||
    clearResponseContent() {
 | 
			
		||||
        this.currentResponse = '';
 | 
			
		||||
        this.currentQuestion = '';
 | 
			
		||||
        this.isLoading = false;
 | 
			
		||||
        this.isStreaming = false;
 | 
			
		||||
        this.headerText = 'AI Response';
 | 
			
		||||
        this.showTextInput = true;
 | 
			
		||||
        this.accumulatedResponse = '';
 | 
			
		||||
        this.requestUpdate();
 | 
			
		||||
        this.renderContent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleInputFocus() {
 | 
			
		||||
        this.isInputFocused = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    focusTextInput() {
 | 
			
		||||
        requestAnimationFrame(() => {
 | 
			
		||||
            const textInput = this.shadowRoot?.getElementById('textInput');
 | 
			
		||||
            if (textInput) {
 | 
			
		||||
                textInput.focus();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    closeIfNoContent() {
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
            const { ipcRenderer } = window.require('electron');
 | 
			
		||||
            ipcRenderer.invoke('force-close-window', 'ask');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    loadScript(src) {
 | 
			
		||||
        return new Promise((resolve, reject) => {
 | 
			
		||||
@ -874,114 +969,6 @@ export class AskView extends LitElement {
 | 
			
		||||
        return text;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connectedCallback() {
 | 
			
		||||
        super.connectedCallback();
 | 
			
		||||
 | 
			
		||||
        console.log('📱 AskView connectedCallback - IPC 이벤트 리스너 설정');
 | 
			
		||||
 | 
			
		||||
        document.addEventListener('click', this.handleDocumentClick, true);
 | 
			
		||||
        document.addEventListener('keydown', this.handleEscKey);
 | 
			
		||||
 | 
			
		||||
        this.resizeObserver = new ResizeObserver(entries => {
 | 
			
		||||
            for (const entry of entries) {
 | 
			
		||||
                const needed = entry.contentRect.height;
 | 
			
		||||
                const current = window.innerHeight;
 | 
			
		||||
 | 
			
		||||
                if (needed > current - 4) {
 | 
			
		||||
                    this.requestWindowResize(Math.ceil(needed));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const container = this.shadowRoot?.querySelector('.ask-container');
 | 
			
		||||
        if (container) this.resizeObserver.observe(container);
 | 
			
		||||
 | 
			
		||||
        this.handleQuestionFromAssistant = (event, question) => {
 | 
			
		||||
            console.log('📨 AskView: Received question from ListenView:', question);
 | 
			
		||||
            this.currentResponse = '';
 | 
			
		||||
            this.isStreaming = false;
 | 
			
		||||
            this.requestUpdate();
 | 
			
		||||
 | 
			
		||||
            this.currentQuestion = question;
 | 
			
		||||
            this.isLoading = true;
 | 
			
		||||
            this.showTextInput = false;
 | 
			
		||||
            this.headerText = 'analyzing screen...';
 | 
			
		||||
            this.startHeaderAnimation();
 | 
			
		||||
            this.requestUpdate();
 | 
			
		||||
 | 
			
		||||
            this.processAssistantQuestion(question);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
            const { ipcRenderer } = window.require('electron');
 | 
			
		||||
            ipcRenderer.on('ask-global-send', this.handleGlobalSendRequest);
 | 
			
		||||
            ipcRenderer.on('receive-question-from-assistant', this.handleQuestionFromAssistant);
 | 
			
		||||
            ipcRenderer.on('hide-text-input', () => {
 | 
			
		||||
                console.log('📤 Hide text input signal received');
 | 
			
		||||
                this.showTextInput = false;
 | 
			
		||||
                this.requestUpdate();
 | 
			
		||||
            });
 | 
			
		||||
            ipcRenderer.on('window-hide-animation', () => {
 | 
			
		||||
                console.log('📤 Ask window hiding - clearing response content');
 | 
			
		||||
                setTimeout(() => {
 | 
			
		||||
                    this.clearResponseContent();
 | 
			
		||||
                }, 250);
 | 
			
		||||
            });
 | 
			
		||||
            ipcRenderer.on('window-blur', this.handleWindowBlur);
 | 
			
		||||
            ipcRenderer.on('window-did-show', () => {
 | 
			
		||||
                if (!this.currentResponse && !this.isLoading && !this.isStreaming) {
 | 
			
		||||
                    this.focusTextInput();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            ipcRenderer.on('ask-response-chunk', this.handleStreamChunk);
 | 
			
		||||
            ipcRenderer.on('ask-response-stream-end', this.handleStreamEnd);
 | 
			
		||||
 | 
			
		||||
            ipcRenderer.on('scroll-response-up', () => this.handleScroll('up'));
 | 
			
		||||
            ipcRenderer.on('scroll-response-down', () => this.handleScroll('down'));
 | 
			
		||||
            console.log('✅ AskView: IPC 이벤트 리스너 등록 완료');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    disconnectedCallback() {
 | 
			
		||||
        super.disconnectedCallback();
 | 
			
		||||
        this.resizeObserver?.disconnect();
 | 
			
		||||
 | 
			
		||||
        console.log('📱 AskView disconnectedCallback - IPC 이벤트 리스너 제거');
 | 
			
		||||
 | 
			
		||||
        document.removeEventListener('click', this.handleDocumentClick, true);
 | 
			
		||||
        document.removeEventListener('keydown', this.handleEscKey);
 | 
			
		||||
 | 
			
		||||
        if (this.copyTimeout) {
 | 
			
		||||
            clearTimeout(this.copyTimeout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.headerAnimationTimeout) {
 | 
			
		||||
            clearTimeout(this.headerAnimationTimeout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this.streamingTimeout) {
 | 
			
		||||
            clearTimeout(this.streamingTimeout);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Object.values(this.lineCopyTimeouts).forEach(timeout => clearTimeout(timeout));
 | 
			
		||||
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
            const { ipcRenderer } = window.require('electron');
 | 
			
		||||
            ipcRenderer.removeListener('ask-global-send', this.handleGlobalSendRequest);
 | 
			
		||||
            ipcRenderer.removeListener('hide-text-input', () => { });
 | 
			
		||||
            ipcRenderer.removeListener('window-hide-animation', () => { });
 | 
			
		||||
            ipcRenderer.removeListener('window-blur', this.handleWindowBlur);
 | 
			
		||||
 | 
			
		||||
            ipcRenderer.removeListener('ask-response-chunk', this.handleStreamChunk);
 | 
			
		||||
            ipcRenderer.removeListener('ask-response-stream-end', this.handleStreamEnd);
 | 
			
		||||
 | 
			
		||||
            ipcRenderer.removeListener('scroll-response-up', () => this.handleScroll('up'));
 | 
			
		||||
            ipcRenderer.removeListener('scroll-response-down', () => this.handleScroll('down'));
 | 
			
		||||
            console.log('✅ AskView: IPC 이벤트 리스너 제거 완료');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleScroll(direction) {
 | 
			
		||||
        const scrollableElement = this.shadowRoot.querySelector('#responseContainer');
 | 
			
		||||
        if (scrollableElement) {
 | 
			
		||||
@ -1124,18 +1111,6 @@ export class AskView extends LitElement {
 | 
			
		||||
        this.adjustWindowHeightThrottled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    clearResponseContent() {
 | 
			
		||||
        this.currentResponse = '';
 | 
			
		||||
        this.currentQuestion = '';
 | 
			
		||||
        this.isLoading = false;
 | 
			
		||||
        this.isStreaming = false;
 | 
			
		||||
        this.headerText = 'AI Response';
 | 
			
		||||
        this.showTextInput = true;
 | 
			
		||||
        this.accumulatedResponse = '';
 | 
			
		||||
        this.requestUpdate();
 | 
			
		||||
        this.renderContent(); // 👈 updateResponseContent() 대신 renderContent() 호출
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    requestWindowResize(targetHeight) {
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
@ -1180,13 +1155,6 @@ export class AskView extends LitElement {
 | 
			
		||||
            .replace(/`(.*?)`/g, '<code>$1</code>');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    closeResponsePanel() {
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
            const { ipcRenderer } = window.require('electron');
 | 
			
		||||
            ipcRenderer.invoke('force-close-window', 'ask');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fixIncompleteMarkdown(text) {
 | 
			
		||||
        if (!text) return text;
 | 
			
		||||
 | 
			
		||||
@ -1224,29 +1192,6 @@ export class AskView extends LitElement {
 | 
			
		||||
        return text;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ✨ processAssistantQuestion 수정
 | 
			
		||||
    async processAssistantQuestion(question) {
 | 
			
		||||
        this.currentQuestion = question;
 | 
			
		||||
        this.showTextInput = false;
 | 
			
		||||
        this.isLoading = true;
 | 
			
		||||
        this.isStreaming = false;
 | 
			
		||||
        this.currentResponse = '';
 | 
			
		||||
        this.accumulatedResponse = '';
 | 
			
		||||
        this.startHeaderAnimation();
 | 
			
		||||
        this.requestUpdate();
 | 
			
		||||
        this.renderContent();
 | 
			
		||||
 | 
			
		||||
        if (window.require) {
 | 
			
		||||
            const { ipcRenderer } = window.require('electron');
 | 
			
		||||
            ipcRenderer.invoke('ask:sendMessage', question).catch(error => {
 | 
			
		||||
                console.error('Error processing assistant question:', error);
 | 
			
		||||
                this.isLoading = false;
 | 
			
		||||
                this.isStreaming = false;
 | 
			
		||||
                this.currentResponse = `Error: ${error.message}`;
 | 
			
		||||
                this.renderContent();
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleCopy() {
 | 
			
		||||
        if (this.copyState === 'copied') return;
 | 
			
		||||
@ -1316,10 +1261,9 @@ export class AskView extends LitElement {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async handleSendText() {
 | 
			
		||||
    async handleSendText(e, overridingText = '') {
 | 
			
		||||
        const textInput = this.shadowRoot?.getElementById('textInput');
 | 
			
		||||
        if (!textInput) return;
 | 
			
		||||
        const text = textInput.value.trim();
 | 
			
		||||
        const text = (overridingText || textInput?.value || '').trim();
 | 
			
		||||
        if (!text) return;
 | 
			
		||||
 | 
			
		||||
        textInput.value = '';
 | 
			
		||||
@ -1377,37 +1321,10 @@ export class AskView extends LitElement {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    focusTextInput() {
 | 
			
		||||
        requestAnimationFrame(() => {
 | 
			
		||||
            const textInput = this.shadowRoot?.getElementById('textInput');
 | 
			
		||||
            if (textInput) {
 | 
			
		||||
                textInput.focus();
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    firstUpdated() {
 | 
			
		||||
        setTimeout(() => this.adjustWindowHeight(), 200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleGlobalSendRequest() {
 | 
			
		||||
        const textInput = this.shadowRoot?.getElementById('textInput');
 | 
			
		||||
 | 
			
		||||
        if (!this.showTextInput) {
 | 
			
		||||
            this.showTextInput = true;
 | 
			
		||||
            this.requestUpdate();
 | 
			
		||||
            this.focusTextInput();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!textInput) return;
 | 
			
		||||
 | 
			
		||||
        textInput.focus();
 | 
			
		||||
 | 
			
		||||
        if (!textInput.value.trim()) return;
 | 
			
		||||
 | 
			
		||||
        this.handleSendText();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getTruncatedQuestion(question, maxLength = 30) {
 | 
			
		||||
        if (!question) return '';
 | 
			
		||||
@ -1415,24 +1332,7 @@ export class AskView extends LitElement {
 | 
			
		||||
        return question.substring(0, maxLength) + '...';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleInputFocus() {
 | 
			
		||||
        this.isInputFocused = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handleInputBlur(e) {
 | 
			
		||||
        this.isInputFocused = false;
 | 
			
		||||
 | 
			
		||||
        // 잠시 후 포커스가 다른 곳으로 갔는지 확인
 | 
			
		||||
        setTimeout(() => {
 | 
			
		||||
            const activeElement = this.shadowRoot?.activeElement || document.activeElement;
 | 
			
		||||
            const textInput = this.shadowRoot?.getElementById('textInput');
 | 
			
		||||
 | 
			
		||||
            // 포커스가 AskView 내부가 아니고, 응답이 없는 경우
 | 
			
		||||
            if (!this.currentResponse && !this.isLoading && !this.isStreaming && activeElement !== textInput && !this.isInputFocused) {
 | 
			
		||||
                this.closeIfNoContent();
 | 
			
		||||
            }
 | 
			
		||||
        }, 200);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        const hasResponse = this.isLoading || this.currentResponse || this.isStreaming;
 | 
			
		||||
@ -1470,7 +1370,7 @@ export class AskView extends LitElement {
 | 
			
		||||
                                    <path d="M20 6L9 17l-5-5" />
 | 
			
		||||
                                </svg>
 | 
			
		||||
                            </button>
 | 
			
		||||
                            <button class="close-button" @click=${this.closeResponsePanel}>
 | 
			
		||||
                            <button class="close-button" @click=${this.handleCloseAskWindow}>
 | 
			
		||||
                                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
 | 
			
		||||
                                    <line x1="18" y1="6" x2="6" y2="18" />
 | 
			
		||||
                                    <line x1="6" y1="6" x2="18" y2="18" />
 | 
			
		||||
@ -1493,7 +1393,6 @@ export class AskView extends LitElement {
 | 
			
		||||
                        placeholder="Ask about your screen or audio"
 | 
			
		||||
                        @keydown=${this.handleTextKeydown}
 | 
			
		||||
                        @focus=${this.handleInputFocus}
 | 
			
		||||
                        @blur=${this.handleInputBlur}
 | 
			
		||||
                    />
 | 
			
		||||
                    <button
 | 
			
		||||
                        class="submit-btn"
 | 
			
		||||
 | 
			
		||||
@ -412,14 +412,7 @@ export class SummaryView extends LitElement {
 | 
			
		||||
            const { ipcRenderer } = window.require('electron');
 | 
			
		||||
 | 
			
		||||
            try {
 | 
			
		||||
                const isAskViewVisible = await ipcRenderer.invoke('is-ask-window-visible', 'ask');
 | 
			
		||||
 | 
			
		||||
                if (!isAskViewVisible) {
 | 
			
		||||
                    await ipcRenderer.invoke('toggle-feature', 'ask');
 | 
			
		||||
                    await new Promise(resolve => setTimeout(resolve, 100));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                const result = await ipcRenderer.invoke('send-question-to-ask', requestText);
 | 
			
		||||
                const result = await ipcRenderer.invoke('ask:sendQuestionToMain', requestText);
 | 
			
		||||
 | 
			
		||||
                if (result.success) {
 | 
			
		||||
                    console.log('✅ Question sent to AskView successfully');
 | 
			
		||||
 | 
			
		||||
@ -76,8 +76,16 @@ function updateLayout() {
 | 
			
		||||
let movementManager = null;
 | 
			
		||||
const windowBridge = require('../bridge/windowBridge');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async function toggleFeature(featureName) {
 | 
			
		||||
/**
 | 
			
		||||
 * 
 | 
			
		||||
 * @param {'listen'|'ask'|'settings'} featureName
 | 
			
		||||
 * @param {{
 | 
			
		||||
*   listen?:   { targetVisibility?: 'show'|'hide' },
 | 
			
		||||
*   ask?:      { targetVisibility?: 'show'|'hide', questionText?: string },
 | 
			
		||||
*   settings?: { targetVisibility?: 'show'|'hide' }
 | 
			
		||||
* }} [options={}]
 | 
			
		||||
*/
 | 
			
		||||
async function toggleFeature(featureName, options = {}) {
 | 
			
		||||
    if (!windowPool.get(featureName) && currentHeaderState === 'main') {
 | 
			
		||||
        createFeatureWindows(windowPool.get('header'));
 | 
			
		||||
    }
 | 
			
		||||
@ -117,14 +125,27 @@ async function toggleFeature(featureName) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const questionText = options?.ask?.questionText ?? null;
 | 
			
		||||
        const targetVisibility = options?.ask?.targetVisibility ?? null;
 | 
			
		||||
        if (askWindow.isVisible()) {
 | 
			
		||||
            askWindow.webContents.send('ask-global-send');
 | 
			
		||||
            if (questionText) {
 | 
			
		||||
                askWindow.webContents.send('ask:sendQuestionToRenderer', questionText);
 | 
			
		||||
            } else {
 | 
			
		||||
                updateLayout();
 | 
			
		||||
                if (targetVisibility === 'show') {
 | 
			
		||||
                    askWindow.webContents.send('ask:showTextInput');
 | 
			
		||||
                } else {
 | 
			
		||||
                    askWindow.webContents.send('window-hide-animation');
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            console.log('[WindowManager] Showing hidden Ask window');
 | 
			
		||||
            askWindow.show();
 | 
			
		||||
            updateLayout();
 | 
			
		||||
            if (questionText) {
 | 
			
		||||
                askWindow.webContents.send('ask:sendQuestionToRenderer', questionText);
 | 
			
		||||
            }
 | 
			
		||||
            askWindow.webContents.send('window-show-animation');
 | 
			
		||||
            askWindow.webContents.send('window-did-show');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -238,8 +259,6 @@ function createFeatureWindows(header, namesToCreate) {
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ask.on('blur',()=>ask.webContents.send('window-blur'));
 | 
			
		||||
                
 | 
			
		||||
                // Open DevTools in development
 | 
			
		||||
                if (!app.isPackaged) {
 | 
			
		||||
@ -532,61 +551,6 @@ function createWindows() {
 | 
			
		||||
        updateLayout();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('toggle-all-windows-visibility', () => toggleAllWindowsVisibility());
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('toggle-feature', async (event, featureName) => {
 | 
			
		||||
        return toggleFeature(featureName);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('send-question-to-ask', (event, question) => {
 | 
			
		||||
        const askWindow = windowPool.get('ask');
 | 
			
		||||
        if (askWindow && !askWindow.isDestroyed()) {
 | 
			
		||||
            console.log('📨 Main process: Sending question to AskView', question);
 | 
			
		||||
            askWindow.webContents.send('receive-question-from-assistant', question);
 | 
			
		||||
            return { success: true };
 | 
			
		||||
        } else {
 | 
			
		||||
            console.error('❌ Cannot find AskView window');
 | 
			
		||||
            return { success: false, error: 'AskView window not found' };
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('adjust-window-height', (event, targetHeight) => {
 | 
			
		||||
        const senderWindow = BrowserWindow.fromWebContents(event.sender);
 | 
			
		||||
        if (senderWindow) {
 | 
			
		||||
            const wasResizable = senderWindow.isResizable();
 | 
			
		||||
            if (!wasResizable) {
 | 
			
		||||
                senderWindow.setResizable(true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const currentBounds = senderWindow.getBounds();
 | 
			
		||||
            const minHeight = senderWindow.getMinimumSize()[1];
 | 
			
		||||
            const maxHeight = senderWindow.getMaximumSize()[1];
 | 
			
		||||
            
 | 
			
		||||
            let adjustedHeight;
 | 
			
		||||
            if (maxHeight === 0) {
 | 
			
		||||
                adjustedHeight = Math.max(minHeight, targetHeight);
 | 
			
		||||
            } else {
 | 
			
		||||
                adjustedHeight = Math.max(minHeight, Math.min(maxHeight, targetHeight));
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            senderWindow.setSize(currentBounds.width, adjustedHeight, false);
 | 
			
		||||
 | 
			
		||||
            if (!wasResizable) {
 | 
			
		||||
                senderWindow.setResizable(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            updateLayout();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.on('session-did-close', () => {
 | 
			
		||||
        const listenWindow = windowPool.get('listen');
 | 
			
		||||
        if (listenWindow && listenWindow.isVisible()) {
 | 
			
		||||
            console.log('[WindowManager] Session closed, hiding listen window.');
 | 
			
		||||
            listenWindow.hide();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return windowPool;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -617,6 +581,12 @@ function loadAndRegisterShortcuts(movementManager) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function setupIpcHandlers(movementManager) {
 | 
			
		||||
    setupApiKeyIPC();
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('quit-application', () => {
 | 
			
		||||
        app.quit();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    screen.on('display-added', (event, newDisplay) => {
 | 
			
		||||
        console.log('[Display] New display added:', newDisplay.id);
 | 
			
		||||
    });
 | 
			
		||||
@ -631,107 +601,10 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    screen.on('display-metrics-changed', (event, display, changedMetrics) => {
 | 
			
		||||
        console.log('[Display] Display metrics changed:', display.id, changedMetrics);
 | 
			
		||||
        // console.log('[Display] Display metrics changed:', display.id, changedMetrics);
 | 
			
		||||
        updateLayout();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 1. 스트리밍 데이터 조각(chunk)을 받아서 ask 창으로 전달
 | 
			
		||||
    ipcMain.on('ask-response-chunk', (event, { token }) => {
 | 
			
		||||
        const askWindow = windowPool.get('ask');
 | 
			
		||||
        if (askWindow && !askWindow.isDestroyed()) {
 | 
			
		||||
            // renderer.js가 보낸 토큰을 AskView.js로 그대로 전달합니다.
 | 
			
		||||
            askWindow.webContents.send('ask-response-chunk', { token });
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 2. 스트리밍 종료 신호를 받아서 ask 창으로 전달
 | 
			
		||||
    ipcMain.on('ask-response-stream-end', () => {
 | 
			
		||||
        const askWindow = windowPool.get('ask');
 | 
			
		||||
        if (askWindow && !askWindow.isDestroyed()) {
 | 
			
		||||
            askWindow.webContents.send('ask-response-stream-end');
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.on('animation-finished', (event) => {
 | 
			
		||||
        const win = BrowserWindow.fromWebContents(event.sender);
 | 
			
		||||
        if (win && !win.isDestroyed()) {
 | 
			
		||||
            console.log(`[WindowManager] Hiding window after animation.`);
 | 
			
		||||
            win.hide();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.on('show-settings-window', (event, bounds) => {
 | 
			
		||||
        if (!bounds) return;  
 | 
			
		||||
        const win = windowPool.get('settings');
 | 
			
		||||
 | 
			
		||||
        if (win && !win.isDestroyed()) {
 | 
			
		||||
            if (settingsHideTimer) {
 | 
			
		||||
                clearTimeout(settingsHideTimer);
 | 
			
		||||
                settingsHideTimer = null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Adjust position based on button bounds
 | 
			
		||||
            const header = windowPool.get('header');
 | 
			
		||||
            const headerBounds = header?.getBounds() ?? { x: 0, y: 0 };
 | 
			
		||||
            const settingsBounds = win.getBounds();
 | 
			
		||||
 | 
			
		||||
            const disp = getCurrentDisplay(header);
 | 
			
		||||
            const { x: waX, y: waY, width: waW, height: waH } = disp.workArea;
 | 
			
		||||
 | 
			
		||||
            let x = Math.round(headerBounds.x + (bounds?.x ?? 0) + (bounds?.width ?? 0) / 2 - settingsBounds.width / 2);
 | 
			
		||||
            let y = Math.round(headerBounds.y + (bounds?.y ?? 0) + (bounds?.height ?? 0) + 31);
 | 
			
		||||
 | 
			
		||||
            x = Math.max(waX + 10, Math.min(waX + waW - settingsBounds.width - 10, x));
 | 
			
		||||
            y = Math.max(waY + 10, Math.min(waY + waH - settingsBounds.height - 10, y));
 | 
			
		||||
 | 
			
		||||
            win.setBounds({ x, y });
 | 
			
		||||
            win.__lockedByButton = true;
 | 
			
		||||
            console.log(`[WindowManager] Positioning settings window at (${x}, ${y}) based on button bounds.`);
 | 
			
		||||
            
 | 
			
		||||
            win.show();
 | 
			
		||||
            win.moveTop();
 | 
			
		||||
            win.setAlwaysOnTop(true);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.on('hide-settings-window', (event) => {
 | 
			
		||||
        const window = windowPool.get("settings");
 | 
			
		||||
        if (window && !window.isDestroyed()) {
 | 
			
		||||
            if (settingsHideTimer) {
 | 
			
		||||
                clearTimeout(settingsHideTimer);
 | 
			
		||||
            }
 | 
			
		||||
            settingsHideTimer = setTimeout(() => {
 | 
			
		||||
                if (window && !window.isDestroyed()) {
 | 
			
		||||
                    window.setAlwaysOnTop(false);
 | 
			
		||||
                    window.hide();
 | 
			
		||||
                }
 | 
			
		||||
                settingsHideTimer = null;
 | 
			
		||||
            }, 200);
 | 
			
		||||
            
 | 
			
		||||
            window.__lockedByButton = false;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.on('cancel-hide-settings-window', (event) => {
 | 
			
		||||
        if (settingsHideTimer) {
 | 
			
		||||
            clearTimeout(settingsHideTimer);
 | 
			
		||||
            settingsHideTimer = null;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('quit-application', () => {
 | 
			
		||||
        app.quit();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('is-ask-window-visible', (event, windowName) => {
 | 
			
		||||
        const window = windowPool.get(windowName);
 | 
			
		||||
        if (window && !window.isDestroyed()) {
 | 
			
		||||
            return window.isVisible();
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('toggle-content-protection', () => {
 | 
			
		||||
        isContentProtectionOn = !isContentProtectionOn;
 | 
			
		||||
        console.log(`[Protection] Content protection toggled to: ${isContentProtectionOn}`);
 | 
			
		||||
@ -827,8 +700,6 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
        console.log('Opening personalization page:', personalizeUrl);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    setupApiKeyIPC();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('resize-header-window', (event, { width, height }) => {
 | 
			
		||||
        const header = windowPool.get('header');
 | 
			
		||||
@ -952,12 +823,32 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('force-close-window', (event, windowName) => {
 | 
			
		||||
        const window = windowPool.get(windowName);
 | 
			
		||||
        if (window && !window.isDestroyed()) {
 | 
			
		||||
            console.log(`[WindowManager] Force closing window: ${windowName}`);
 | 
			
		||||
    ipcMain.handle('adjust-window-height', (event, targetHeight) => {
 | 
			
		||||
        const senderWindow = BrowserWindow.fromWebContents(event.sender);
 | 
			
		||||
        if (senderWindow) {
 | 
			
		||||
            const wasResizable = senderWindow.isResizable();
 | 
			
		||||
            if (!wasResizable) {
 | 
			
		||||
                senderWindow.setResizable(true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            window.webContents.send('window-hide-animation');
 | 
			
		||||
            const currentBounds = senderWindow.getBounds();
 | 
			
		||||
            const minHeight = senderWindow.getMinimumSize()[1];
 | 
			
		||||
            const maxHeight = senderWindow.getMaximumSize()[1];
 | 
			
		||||
            
 | 
			
		||||
            let adjustedHeight;
 | 
			
		||||
            if (maxHeight === 0) {
 | 
			
		||||
                adjustedHeight = Math.max(minHeight, targetHeight);
 | 
			
		||||
            } else {
 | 
			
		||||
                adjustedHeight = Math.max(minHeight, Math.min(maxHeight, targetHeight));
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            senderWindow.setSize(currentBounds.width, adjustedHeight, false);
 | 
			
		||||
 | 
			
		||||
            if (!wasResizable) {
 | 
			
		||||
                senderWindow.setResizable(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            updateLayout();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -1140,13 +1031,95 @@ function setupIpcHandlers(movementManager) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    
 | 
			
		||||
    ipcMain.handle('toggle-all-windows-visibility', () => toggleAllWindowsVisibility());
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('close-ask-window-if-empty', async () => {
 | 
			
		||||
        const askWindow = windowPool.get('ask');
 | 
			
		||||
        if (askWindow && !askWindow.isFocused()) {
 | 
			
		||||
            askWindow.hide();
 | 
			
		||||
    ipcMain.handle('toggle-feature', async (event, featureName) => {
 | 
			
		||||
        return toggleFeature(featureName);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.on('animation-finished', (event) => {
 | 
			
		||||
        const win = BrowserWindow.fromWebContents(event.sender);
 | 
			
		||||
        if (win && !win.isDestroyed()) {
 | 
			
		||||
            console.log(`[WindowManager] Hiding window after animation.`);
 | 
			
		||||
            win.hide();
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.on('show-settings-window', (event, bounds) => {
 | 
			
		||||
        if (!bounds) return;  
 | 
			
		||||
        const win = windowPool.get('settings');
 | 
			
		||||
 | 
			
		||||
        if (win && !win.isDestroyed()) {
 | 
			
		||||
            if (settingsHideTimer) {
 | 
			
		||||
                clearTimeout(settingsHideTimer);
 | 
			
		||||
                settingsHideTimer = null;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Adjust position based on button bounds
 | 
			
		||||
            const header = windowPool.get('header');
 | 
			
		||||
            const headerBounds = header?.getBounds() ?? { x: 0, y: 0 };
 | 
			
		||||
            const settingsBounds = win.getBounds();
 | 
			
		||||
 | 
			
		||||
            const disp = getCurrentDisplay(header);
 | 
			
		||||
            const { x: waX, y: waY, width: waW, height: waH } = disp.workArea;
 | 
			
		||||
 | 
			
		||||
            let x = Math.round(headerBounds.x + (bounds?.x ?? 0) + (bounds?.width ?? 0) / 2 - settingsBounds.width / 2);
 | 
			
		||||
            let y = Math.round(headerBounds.y + (bounds?.y ?? 0) + (bounds?.height ?? 0) + 31);
 | 
			
		||||
 | 
			
		||||
            x = Math.max(waX + 10, Math.min(waX + waW - settingsBounds.width - 10, x));
 | 
			
		||||
            y = Math.max(waY + 10, Math.min(waY + waH - settingsBounds.height - 10, y));
 | 
			
		||||
 | 
			
		||||
            win.setBounds({ x, y });
 | 
			
		||||
            win.__lockedByButton = true;
 | 
			
		||||
            console.log(`[WindowManager] Positioning settings window at (${x}, ${y}) based on button bounds.`);
 | 
			
		||||
            
 | 
			
		||||
            win.show();
 | 
			
		||||
            win.moveTop();
 | 
			
		||||
            win.setAlwaysOnTop(true);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.on('hide-settings-window', (event) => {
 | 
			
		||||
        const window = windowPool.get("settings");
 | 
			
		||||
        if (window && !window.isDestroyed()) {
 | 
			
		||||
            if (settingsHideTimer) {
 | 
			
		||||
                clearTimeout(settingsHideTimer);
 | 
			
		||||
            }
 | 
			
		||||
            settingsHideTimer = setTimeout(() => {
 | 
			
		||||
                if (window && !window.isDestroyed()) {
 | 
			
		||||
                    window.setAlwaysOnTop(false);
 | 
			
		||||
                    window.hide();
 | 
			
		||||
                }
 | 
			
		||||
                settingsHideTimer = null;
 | 
			
		||||
            }, 200);
 | 
			
		||||
            
 | 
			
		||||
            window.__lockedByButton = false;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ipcMain.on('cancel-hide-settings-window', (event) => {
 | 
			
		||||
        if (settingsHideTimer) {
 | 
			
		||||
            clearTimeout(settingsHideTimer);
 | 
			
		||||
            settingsHideTimer = null;
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('ask:closeAskWindow', async () => {
 | 
			
		||||
        const askWindow = windowPool.get('ask');
 | 
			
		||||
        if (askWindow) {
 | 
			
		||||
            askWindow.webContents.send('window-hide-animation');
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    ipcMain.handle('ask:sendQuestionToMain', (event, question) => {
 | 
			
		||||
        console.log('📨 Main process: Sending question to AskView', question);
 | 
			
		||||
        toggleFeature('ask', {ask: { questionText: question }});
 | 
			
		||||
        return { success: true };
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1290,7 +1263,7 @@ function updateGlobalShortcuts(keybinds, mainWindow, sendToRenderer, movementMan
 | 
			
		||||
                    callback = () => toggleAllWindowsVisibility();
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'nextStep':
 | 
			
		||||
                    callback = () => toggleFeature('ask');
 | 
			
		||||
                    callback = () => toggleFeature('ask', {ask: { targetVisibility: 'show' }});
 | 
			
		||||
                    break;
 | 
			
		||||
                case 'scrollUp':
 | 
			
		||||
                    callback = () => {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user