-
Notifications
You must be signed in to change notification settings - Fork 1
goateed app #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
goateed app #4
Changes from all commits
131e19c
da6db1c
7c96220
a312772
a08b7a7
3311fdb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ const { retryAndPasteTranscript } = require('./services/retry-transcript'); | |
| const pendingRetryService = require('./services/pending-retry'); | ||
| const sessionManager = require('./services/transcription-session-manager'); | ||
| const { closeSettingsWindow } = require('./settings-window'); | ||
| const { updateHotkey } = require('./shortcuts'); | ||
| const { updateHotkey, handleRecordingToggle } = require('./shortcuts'); | ||
| const { applyLaunchOnStartupPreference } = require('./services/startup'); | ||
| const { applyAutoUpdatePreference } = require('./services/updater'); | ||
| const logger = require('./services/logger'); | ||
|
|
@@ -74,8 +74,25 @@ function setupIpcHandlers(mainWindow) { | |
| ipcMain.handle(CHANNELS.TEST_GROQ_KEY, async (event, apiKey) => validateApiKey(apiKey)); | ||
| ipcMain.handle(CHANNELS.GET_USAGE_STATS, async () => rateLimiter.getUsageStats()); | ||
| ipcMain.handle(CHANNELS.GET_HISTORY, async () => historyService.getHistory()); | ||
| ipcMain.handle(CHANNELS.SEARCH_HISTORY, async (event, query) => historyService.searchHistory(query)); | ||
| ipcMain.handle(CHANNELS.CLEAR_HISTORY, async () => historyService.clearHistory()); | ||
|
|
||
| ipcMain.handle(CHANNELS.GET_TASKS, async () => { | ||
| const historyStore = new Store({ name: 'tasks-history' }); | ||
| return historyStore.get('tasks', []); | ||
| }); | ||
|
|
||
| ipcMain.handle(CHANNELS.TOGGLE_TASK, async (event, taskId) => { | ||
| const historyStore = new Store({ name: 'tasks-history' }); | ||
| const tasks = historyStore.get('tasks', []); | ||
| const task = tasks.find(t => t.id === taskId); | ||
| if (task) { | ||
| task.completed = !task.completed; | ||
| historyStore.set('tasks', tasks); | ||
| } | ||
| return tasks; | ||
|
Comment on lines
+80
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Expectation:
# - `new Store(` matches are present
# - no `require('electron-store')` match is present in src/main/ipc.js
rg -n "new Store\\(|require\\(['\"]electron-store['\"]\\)" src/main/ipc.jsRepository: JStaRFilms/Koe Length of output: 197 🏁 Script executed: head -30 src/main/ipc.jsRepository: JStaRFilms/Koe Length of output: 1291
The module never imports Fixconst logger = require('./services/logger');
const fs = require('fs');
+const Store = require('electron-store');🤖 Prompt for AI Agents |
||
| }); | ||
|
|
||
| ipcMain.handle(CHANNELS.RETRY_HISTORY_ENTRY, async (event, entryId) => { | ||
| return retryAndPasteTranscript(entryId, { | ||
| beforePaste: hideSettingsBeforePaste | ||
|
|
@@ -114,6 +131,11 @@ function setupIpcHandlers(mainWindow) { | |
| closeSettingsWindow(); | ||
| }); | ||
|
|
||
| ipcMain.on(CHANNELS.TOGGLE_RECORDING, (event, options) => { | ||
| handleRecordingToggle(mainWindow, options); | ||
| }); | ||
|
|
||
|
|
||
| ipcMain.on(CHANNELS.AUDIO_SEGMENT, (event, audioData) => { | ||
| sessionManager.handleSegment(audioData).catch((error) => { | ||
| logger.error('[Pipeline] Failed to enqueue audio segment:', error); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ const { setupIpcHandlers } = require('./ipc'); | |
| const { createSettingsWindow } = require('./settings-window'); | ||
| const { getPillBounds, pinPillWindow } = require('./services/pill-window'); | ||
| const { getSetting } = require('./services/settings'); | ||
| const meetingDetector = require('./services/meeting-detector'); | ||
| const { applyLaunchOnStartupPreference } = require('./services/startup'); | ||
| const { applyAutoUpdatePreference } = require('./services/updater'); | ||
| const sessionManager = require('./services/transcription-session-manager'); | ||
|
|
@@ -81,6 +82,7 @@ app.whenReady().then(() => { | |
| setupTray(mainWindow); | ||
| registerShortcuts(mainWindow); | ||
| setupIpcHandlers(mainWindow); | ||
| meetingDetector.init(mainWindow); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Resource leak:
Proposed fix app.on('before-quit', () => {
app.isQuitting = true;
unregisterShortcuts();
+ meetingDetector.stopMonitoring();
sessionManager.shutdown();
});Also applies to: 106-110 🤖 Prompt for AI Agents |
||
|
|
||
| applyLaunchOnStartupPreference(getSetting('launchOnStartup') !== false); | ||
| applyAutoUpdatePreference(getSetting('autoUpdate') !== false); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,19 @@ | ||||||
| const logger = require('./logger'); | ||||||
|
|
||||||
| class EmailService { | ||||||
| async sendMeetingSummary(to, summary) { | ||||||
| if (!to) { | ||||||
| logger.warn('[EmailService] No email address provided for summary.'); | ||||||
| return; | ||||||
| } | ||||||
|
|
||||||
| // Simulating email sending | ||||||
| logger.info(`[EmailService] Sending meeting summary to ${to}...`); | ||||||
| logger.debug('[EmailService] Summary content:', summary); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PII exposure: meeting summary logged at debug level. The Proposed fix- logger.debug('[EmailService] Summary content:', summary);
+ logger.debug('[EmailService] Summary length:', summary?.length || 0);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
|
|
||||||
| // In a real app, you'd use a service like SendGrid, Mailgun, or Nodemailer | ||||||
| return Promise.resolve({ success: true }); | ||||||
| } | ||||||
|
Comment on lines
+3
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stub implementation with This is a placeholder that doesn't actually send emails, but Consider either:
🤖 Prompt for AI Agents |
||||||
| } | ||||||
|
|
||||||
| module.exports = new EmailService(); | ||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,82 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const { exec } = require('child_process'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const { Notification } = require('electron'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const logger = require('./logger'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const MEETING_PROCESSES = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Zoom.exe', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Teams.exe', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'ms-teams.exe', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Slack.exe', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Webex.exe' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+5
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Meeting process detection only works on Windows. The
The current implementation will never detect meetings on non-Windows platforms. Proposed fix for cross-platform support-const MEETING_PROCESSES = [
- 'Zoom.exe',
- 'Teams.exe',
- 'ms-teams.exe',
- 'Slack.exe',
- 'Webex.exe'
-];
+const MEETING_PROCESSES_WIN = [
+ 'Zoom.exe',
+ 'Teams.exe',
+ 'ms-teams.exe',
+ 'Slack.exe',
+ 'Webex.exe'
+];
+
+const MEETING_PROCESSES_MAC = [
+ 'zoom.us',
+ 'Microsoft Teams',
+ 'Slack',
+ 'Webex'
+];
+
+const MEETING_PROCESSES_LINUX = [
+ 'zoom',
+ 'teams',
+ 'slack',
+ 'webex'
+];
+
+function getMeetingProcesses() {
+ if (process.platform === 'win32') return MEETING_PROCESSES_WIN;
+ if (process.platform === 'darwin') return MEETING_PROCESSES_MAC;
+ return MEETING_PROCESSES_LINUX;
+}Then update - const active = MEETING_PROCESSES.some(proc => stdout.includes(proc));
+ const processes = getMeetingProcesses();
+ const active = processes.some(proc => stdout.toLowerCase().includes(proc.toLowerCase()));🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| class MeetingDetector { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| constructor() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.interval = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.isMeetingActive = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.mainWindow = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| init(mainWindow) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.mainWindow = mainWindow; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.startMonitoring(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| startMonitoring() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (this.interval) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| this.interval = setInterval(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.checkMeetingStatus(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }, 30000); // Check every 30 seconds | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| this.checkMeetingStatus(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| stopMonitoring() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (this.interval) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| clearInterval(this.interval); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.interval = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| checkMeetingStatus() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const command = process.platform === 'win32' ? 'tasklist' : 'ps -e'; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| exec(command, (error, stdout) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.error('[MeetingDetector] Failed to list processes:', error); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const active = MEETING_PROCESSES.some(proc => stdout.includes(proc)); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Process detection may have false positives. Using Proposed improvement- const active = MEETING_PROCESSES.some(proc => stdout.includes(proc));
+ const active = MEETING_PROCESSES.some(proc => {
+ // Use regex with word boundary for more precise matching
+ const pattern = new RegExp(`\\b${proc.replace('.', '\\.')}\\b`, 'i');
+ return pattern.test(stdout);
+ });📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (active && !this.isMeetingActive) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.onMeetingDetected(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| this.isMeetingActive = active; | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| onMeetingDetected() { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| logger.info('[MeetingDetector] Meeting detected!'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const notification = new Notification({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| title: 'Koe - Meeting Detected', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| body: 'Would you like to join the meeting to take notes and summarize?', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| silent: false | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| notification.show(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| notification.on('click', () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (this.mainWindow && !this.mainWindow.isDestroyed()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const { CHANNELS } = require('../../shared/constants'); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.mainWindow.webContents.send(CHANNELS.MEETING_DETECTED); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.mainWindow.show(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+70
to
+78
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Notification shown before click handler registration.
Proposed fix const notification = new Notification({
title: 'Koe - Meeting Detected',
body: 'Would you like to join the meeting to take notes and summarize?',
silent: false
});
- notification.show();
-
notification.on('click', () => {
if (this.mainWindow && !this.mainWindow.isDestroyed()) {
const { CHANNELS } = require('../../shared/constants');
this.mainWindow.webContents.send(CHANNELS.MEETING_DETECTED);
this.mainWindow.show();
}
});
+
+ notification.show();
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| module.exports = new MeetingDetector(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
smartContextis ignored whencustomPromptis set.The early return bypasses the new context prefix entirely, so Smart Context silently stops working for custom-prompt users.
🧩 Minimal fix
const trimmedPrompt = customPrompt.trim(); if (trimmedPrompt) { - return trimmedPrompt; + return contextPrefix + trimmedPrompt; }📝 Committable suggestion
🤖 Prompt for AI Agents