Voice typing extension that records microphone audio, uploads it to a configured speech-to-text API, and inserts the transcription. Uses the clipboard as a paste fallback.
Note: Binary files aren't shown on the web site. To see all files, please download the extension zipfile.
EGO-A-005 manual_review
extensions should not access the clipboard directly
Direct clipboard access via `St.Clipboard.get_default()` requires reviewer scrutiny.
extension.js:363
St.Clipboard.get_default()
extension.js:661
St.Clipboard.get_default()
EGO-L-004 warning
main loop sources should be removed in disable()
Main loop sources assigned in `enable()` are missing matching removals in `disable()` or its helper methods.
extension.js:401
GLib.timeout_add(GLib.PRIORITY_DEFAULT, 250, () => {
// Only restore if the selection still holds the transcription we
// wrote — otherwise the user or app has put something newer there
// and we shouldn't overwrite it.
const maybeRestore = (
1. You are getting too many instance of gsettings with `this.getSettings()` in `prefs.js`. Get it once and hold it in a variable. You can use that instance. 2. Please use `connectObject()` and `disconnectObject()` so it is easier to track for cleanup. 3. Timeout should be removed before creating a new one (line 207 `extension.js`). 4. `this._destroying` is a bad practice. After destroy you should null out the property holding the instance so it is not called again. 5. Please remove all the artifacts made by AI. like `=== 'function'` and unnecessary try-catch wrappers. For example, something like line 1046 `extension.js` shouldn't be wrapped with try-catch.
Thanks for the review — all five points are addressed in this version. 1. Repeated this.getSettings() in prefs.js fillPreferencesWindow now fetches the settings object once (const settings = this.getSettings();) and every binding reads/writes through that single instance. 2. connectObject() / disconnectObject() The settings changed::debug-mode handler and the panel-button click handler now use connectObject(..., this). Cleanup is a single this._settings.disconnectObject(this) (plus the gesture) in destroy(), replacing the manual _signalConnections array and its disconnect loop. 3. Recording timeout recreated without removal _startFileRecording now removes any existing recordingTimeout (GLib.source_remove) before scheduling a new one. 4. this._destroying Removed entirely. The extension's disable() already nulls this._indicator, so the re-entrancy guard in destroy() was unnecessary. The async subprocess path that previously checked _destroying now keys off the Gio.Cancellable (cancelled and nulled in destroy()), which is the correct way to short-circuit an in-flight callback after teardown. 5. AI artifacts / unnecessary try-catch Removed the typeof … === 'function' guards and the try-catch wrappers around our own .destroy() calls (including the one at the old line 1046 in disable() and in _destroyDebugWindow). The icon is now disposed by super.destroy() as a child rather than being destroyed manually. The remaining try-catch blocks only wrap genuinely fallible external operations (subprocess launches, D-Bus calls, clipboard/HTTP I/O). Additional cleanup in this version while I was in here: - Tracked and removed a previously orphaned GLib.timeout_add source (clipboard-restore timer) in destroy(). - Guarded Clutter.ClickGesture so older shells that lack it fall back to a button-press-event handler instead of throwing. - Fixed a broken keyval comparison in the shortcut dialog's Escape handling. - Made a notification string a static gettext msgid with a placeholder instead of an interpolated template literal. - Removed a redundant manual delete Main.panel.statusArea[uuid] (the button's destroy() already deregisters it) and an unused field.