Conversation
Pause keyboard polling when hidden, coalesce pointer/head moves per rAF, RAF-throttle live resize, and use sliced Zustand selectors to reduce re-renders. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace null CSP and wildcard asset scope, narrow opener permissions, allowlist music reads with a size cap, cache app icons on disk for convertFileSrc, and validate quick-action launch targets. Co-authored-by: Cursor <cursoragent@cursor.com>
fix(security): harden CSP, asset scope, and IPC file/launch paths
perf: cut IPC storm from keyboard poll, trackpad, and head tracking
fix: unblock Tokio/IPC for speak, macros, STT, and native dialogs
fix: stop profile settings from resetting on startup and switch
- Added a new PartitureView component to the MusicLessonPanel. - Updated the layout to a grid format for better organization. - Introduced a dropdown for selecting built-in and imported songs. - Added transitions for partiture elements in index.css. - Updated translations for "partiture" in English and Greek. - Included new songs "Für Elise," "Minuet in G," "Canon in D," "Morning Mood," and "In the Hall of the Mountain King" to the song library.
feat: add classical songs and partiture lesson layout
…talian, and Portuguese - Introduced new translation files for German (de.ts), Spanish (es.ts), French (fr.ts), Italian (it.ts), and Portuguese (pt.ts). - Each file contains localized strings for various application features, enhancing accessibility for users in these languages.
- Added support for German, Spanish, French, Italian, and Portuguese in the application. - Updated translation files for each new language, enhancing accessibility for a broader user base. - Enhanced keyboard and settings components to accommodate new languages. - Improved voice dictation and text-to-speech functionalities to support additional languages. - Updated README to reflect new language features and predictive text capabilities.
…er focus - Revised the README to better articulate the purpose of ReachPanel, emphasizing its use for individuals unable to use a physical keyboard. - Added a new section detailing the intended setup for single and multi-monitor configurations. - Enhanced the accessibility requirements document to clarify target users and their needs, including typical use cases and caregiver functionalities. - Updated layout descriptions and acceptance criteria to reflect recent changes in user interface and experience.
- Updated the description to specify the target users of ReachPanel, emphasizing its utility for individuals with severe motor disabilities using touchscreen devices. - Clarified the intended setup instructions for single and multi-monitor configurations. - Enhanced the layout descriptions and accessibility features to improve user understanding and experience. - Revised sections on keyboard and mouse functionalities to reflect recent updates and improvements.
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
- Updated README to reflect the addition of offline word packs for predictive text, with English bundled and other languages available for download. - Enhanced accessibility requirements documentation to include details about offline word packs and their learning capabilities. - Implemented new components for managing word packs in the settings panel, allowing users to install and uninstall language packs. - Added backend support for listing, installing, and uninstalling word packs, including database schema updates for managing word pack data. - Improved localization files to include new strings related to word pack management across multiple languages.
feat: enhance predictive text with offline word packs
|
Warning Review limit reached
Next review available in: 9 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe change adds multilingual word packs and localization, music notation, safer file and application handling, synchronized profile and speech state, asynchronous input operations, pointer and resize batching, and updated accessibility and development documentation. ChangesApplication feature and runtime updates
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant SettingsPanel
participant TauriCommands
participant Prediction
participant Database
User->>SettingsPanel: Select language pack action
SettingsPanel->>TauriCommands: Invoke install or uninstall command
TauriCommands->>Prediction: Validate and load pack
Prediction->>Database: Replace or remove pack data
Database-->>TauriCommands: Return refreshed pack metadata
TauriCommands-->>SettingsPanel: Return refreshed pack list
SettingsPanel-->>User: Display localized status
sequenceDiagram
participant MusicLessonPanel
participant PartitureView
participant layoutPartiture
participant PlaybackState
MusicLessonPanel->>PartitureView: Pass song and active note index
PartitureView->>layoutPartiture: Build note layout
layoutPartiture-->>PartitureView: Return staff positions and durations
PlaybackState->>PartitureView: Update active note
PartitureView-->>MusicLessonPanel: Render notation and progress
Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (2 warnings, 1 inconclusive)
✅ Passed checks (2 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 18
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src-tauri/src/tts/winrt.rs (1)
94-119: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winThe 50 second wait cap makes
get_statusreport "idle" during long speech.The loop runs at most 500 iterations of 100 ms. For an utterance longer than 50 s, the loop returns,
speak_textclears the tracked playback at line 170, and closes the player at line 171. The user then loses the remaining audio, andstop_speakingcan no longer cancel it. Loop until playback actually ends, or keep the entry until the player reports a terminal state.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/src/tts/winrt.rs` around lines 94 - 119, The wait_for_playback function’s fixed 500-iteration limit prematurely ends long utterances and clears playback tracking. Remove the 50-second cap so the loop continues until cancellation or a terminal playback state is reported, while preserving the existing state handling and cancellation behavior.src-tauri/capabilities/default.json (1)
17-24: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winRemove the unscoped
opener:allow-open-urlpermission.In Tauri capabilities, raw permission identifiers grant the command without scope restrictions. Line 17 enables
open_urlbroadly, so the scopedopener:allow-open-urlentry cannot limit it toms-settings:*or*. Keep the scoped object only if you need justms-settings:*, or add only the URL schemes/domains you trust.🔒️ Proposed permission tightening
- "opener:allow-open-url", "opener:allow-default-urls", { "identifier": "opener:allow-open-url", "allow": [ { "url": "ms-settings:*" } ] },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/capabilities/default.json` around lines 17 - 24, Remove the unscoped "opener:allow-open-url" entry from the capability permissions array, preserving the scoped permission object for the explicitly allowed ms-settings:* URL pattern.src/App.tsx (1)
37-76: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winStart keyboard polling even when initialization fails.
initperforms many awaited IPC calls before it creates the polling interval. If any call rejects,void init()produces an unhandled rejection andpollIdis never set. Keyboard polling then stays off for the whole session, so sticky modifiers and layout changes stop updating. Add error handling around the setup sequence.🛠️ Proposed fix
const init = async () => { - await loadProfileFiles(); - if (cancelled) return; - ... - await refreshSttCapability(); + try { + await loadProfileFiles(); + if (cancelled) return; + // ... existing setup calls ... + await refreshSttCapability(); + } catch (error) { + console.error("startup init failed", error); + } if (cancelled) return; pollId = window.setInterval(() => {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/App.tsx` around lines 37 - 76, Update the initialization flow in the useEffect’s init function to handle rejected setup calls without leaving polling disabled or producing an unhandled rejection. Ensure the keyboard polling interval is started even when an awaited initialization step fails, while preserving cancellation checks and cleanup through pollId.
🧹 Nitpick comments (12)
src-tauri/src/tts/winrt.rs (1)
139-148: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueNote the serialization cost of the synthesizer lock.
with_synthesizerholds the mutex across the blockingSynthesizeTextToStreamAsync(...).get()call. A concurrentspeak_textblocks for the whole synthesis. The lock is needed becauseSetVoiceandOptionsmutate shared state, so this is a trade-off rather than a defect. If concurrent speech matters, create a per-callSpeechSynthesizerinstead of sharing one.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/src/tts/winrt.rs` around lines 139 - 148, Review the `with_synthesizer` usage in `speak_text`: it holds the shared synthesizer mutex across the blocking `SynthesizeTextToStreamAsync(...).get()` call, serializing concurrent speech. If concurrent speech is required, replace the shared synthesizer path with a per-call `SpeechSynthesizer` while preserving the existing voice, volume, rate, and error handling behavior.src-tauri/src/stt/winrt.rs (1)
151-168: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueCleanup is correct; consider a "starting" flag to avoid duplicate device work.
The loser of a concurrent start now stops, deregisters, and closes its session, so shared state stays consistent. Two callers still build recognizers and open the microphone at the same time. If you want to prevent that, add a
starting: booltoDictationRuntimeand set it during the pre-check at lines 86-93.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/src/stt/winrt.rs` around lines 151 - 168, The concurrent start path still performs duplicate recognizer and microphone setup before detecting an active session. Add a starting flag to DictationRuntime, check and set it during the initial runtime pre-check, reject competing starts while it is set, and reliably clear it on success and every startup error path so later starts are not blocked.src-tauri/src/stt/groq.rs (1)
243-253: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winDo not skip the flush check when no new samples arrived.
Line 245
continues whilebuf.len() <= cursor. If the capture callback stops delivering samples during an utterance, the silence and max-duration checks below never run, and the buffered speech is never transcribed. Treat "no new samples" as zero energy instead of skipping the iteration.♻️ Proposed gate change
let energy = match samples.lock() { Ok(buf) => { if buf.len() <= cursor { - continue; + 0.0 + } else { + let window = TARGET_SAMPLE_RATE as usize / 10; // ~100ms + let start = buf.len().saturating_sub(window).max(cursor); + rms(&buf[start..]) } - let window = TARGET_SAMPLE_RATE as usize / 10; // ~100ms - let start = buf.len().saturating_sub(window).max(cursor); - rms(&buf[start..]) } Err(_) => continue, };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/src/stt/groq.rs` around lines 243 - 253, Update the energy calculation in the capture loop around the samples lock so buf.len() <= cursor yields zero energy instead of continuing. Preserve the existing RMS calculation for new samples, allowing the downstream silence and max-duration flush checks to run even when the capture callback stops delivering samples.src-tauri/src/icons.rs (1)
57-77: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider bounding the icon cache.
icon_cache_keymixes the modification time and length into the key. Every executable update produces a new filename, and the old file stays on disk forever. Add a size or age based cleanup pass at startup, for example remove files older than 30 days.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/src/icons.rs` around lines 57 - 77, Bound the icon cache during startup by adding cleanup to the existing icon cache initialization flow around icon_cache_dir, removing cached files older than the chosen retention period (for example, 30 days) while preserving current directory creation and error propagation behavior.tauri-mcp.toml (1)
4-4: 🔒 Security & Privacy | 🔵 TrivialLimit automatic discovery to trusted workspaces.
The upstream
tauri-mcpconfiguration usesauto_discover = trueto discover Tauri apps in the current directory. Its documented tools include process management, input simulation, JavaScript execution, and IPC calls. (github.com)Because Cursor uses
.cursor/mcp.jsonfor project-scoped tools and managesstdioservers locally, document the trust boundary or make this setup opt-in. Confirm that automatic discovery is intended for every checkout. (docs.cursor.com)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tauri-mcp.toml` at line 4, Update the auto_discover setting in tauri-mcp.toml so automatic Tauri app discovery is opt-in or restricted to explicitly trusted workspaces; document the trust requirement alongside the setting and avoid enabling discovery for every checkout by default.Source: MCP tools
src/hooks/useHeadTracking.ts (1)
63-76: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low valueSet
willReadFrequentlyon the 2D context.The tracking loop calls
getImageDataon every animation frame. Browsers optimize readback when the context declareswillReadFrequently: true. The canvas is created once here, so the option must be passed atgetContexttime.♻️ Proposed refactor
- const ctx = canvas.getContext("2d"); + const ctx = canvas.getContext("2d", { willReadFrequently: true });🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/hooks/useHeadTracking.ts` around lines 63 - 76, Update the getContext call in the track function of useHeadTracking to request the 2D context with willReadFrequently enabled, preserving the existing canvas creation and frame-processing logic.scripts/generate-wordpacks.mjs (1)
18-37: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueAdd a redirect limit to
fetchText.
fetchTextfollowsLocationheaders recursively with no depth limit. A redirect cycle causes unbounded recursion. A small counter removes that risk.♻️ Proposed change
-function fetchText(url) { +function fetchText(url, redirects = 0) { return new Promise((resolve, reject) => { https .get(url, (res) => { if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { - fetchText(res.headers.location).then(resolve, reject); + if (redirects >= 5) { + reject(new Error(`${url} -> too many redirects`)); + res.resume(); + return; + } + fetchText(res.headers.location, redirects + 1).then(resolve, reject); return; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/generate-wordpacks.mjs` around lines 18 - 37, Update fetchText to track redirect depth across recursive Location-header requests and stop following redirects once a small maximum is reached. Reject with an appropriate error when the limit is exceeded, while preserving the existing successful-response and non-redirect error handling.src-tauri/src/lib.rs (2)
671-700: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low valueVerify the bare-host branch against the intended targets.
The bare-host branch accepts
:and buildshttps://{trimmed}. An input such asjavascript:alert(1)passes the character filter and becomeshttps://javascript:alert(1), which the opener rejects or treats as an invalid host. The result is safe, but the error is opaque. Consider validating the host with a stricter pattern, for example a label-dot-label form with an optional port and path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/src/lib.rs` around lines 671 - 700, Tighten the bare-host branch in validate_quick_action_url so it accepts only host-shaped targets, such as label-dot-label domains with an optional port and path, rather than arbitrary colon-containing strings. Preserve the existing allowed schemes and HTTPS prefixing, while rejecting inputs like javascript:alert(1) with the existing URL scheme error.
949-957: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winRun the pack installation off the command thread.
cmd_install_word_packis synchronous andinstall_word_packperforms an HTTP download plus a bulk database import. This PR moved other blocking commands, such ascmd_pick_music_song_fileandcmd_start_dictation, totokio::task::spawn_blocking. Apply the same pattern here so a slow download does not occupy the command thread. Resolve theDatabasefrom theAppHandleinside the closure, becauseStateis not usable across an await point.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/src/lib.rs` around lines 949 - 957, The synchronous cmd_install_word_pack command currently performs blocking download and database work on the command thread. Convert it to the established tokio::task::spawn_blocking pattern used by cmd_pick_music_song_file and cmd_start_dictation, resolve Database from the AppHandle inside the closure rather than capturing State across the await point, run install_word_pack and list_word_packs there, and propagate the resulting errors.src/components/settings/SettingsPanel.tsx (1)
125-127: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract the pack shape into one type.
The object shape
{ language: string; installed: boolean; version: number | null; bundled: boolean }is repeated four times. Declare it once and reuse it in the state and in eachinvokegeneric. This keeps the type aligned withWordPackInfoinsrc-tauri/src/prediction/mod.rs.♻️ Proposed change
+type WordPackInfo = { + language: string; + installed: boolean; + version: number | null; + bundled: boolean; +}; + function WordPackDictionaries({ surface }: { surface: SurfaceColors }) { const { t } = useTranslation(); - const [packs, setPacks] = useState< - { language: string; installed: boolean; version: number | null; bundled: boolean }[] - >([]); + const [packs, setPacks] = useState<WordPackInfo[]>([]);Also applies to: 144-149, 157-187
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/settings/SettingsPanel.tsx` around lines 125 - 127, Declare a shared type for the pack shape near the component, then replace the repeated inline object types in the packs state and all related invoke generics with that type. Keep its fields aligned with WordPackInfo, including nullable version and bundled status.src-tauri/src/db/mod.rs (1)
855-866: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winConsider separating pack score and profile score.
Pack frequencies reach tens of millions. A profile entry used once contributes only 1000. A word from user history therefore ranks below common pack words for a long time. Rank by profile usage first, then by pack frequency, to make learned words appear sooner.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/src/db/mod.rs` around lines 855 - 866, Update the ranking logic around the scores collection and ranked.sort_by so pack frequency and profile usage are tracked separately; order predictions by profile usage descending first, then pack frequency descending, with the existing word tie-breaker. Preserve the limit truncation and frequency conversion behavior in the PredictionEntry mapping.src/components/keyboard/Keyboard.tsx (1)
136-144: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueHoist the typing-locale fallback and verify the consumed signatures.
settings.typingLanguage || "en"is computed twice: once insidehandleKey(Line 137) and again inline in the render body (Line 176). Hoist it to a single component-level constant, next toeffectiveLayoutandrows, and reuse it in both places.Separately,
resolveKeyOutput(Line 138) anddisplayLabel(Line 171) now take this locale as a new parameter. Their definitions are not in this batch. Confirm the parameter position and type match in their source file.♻️ Proposed refactor to hoist the locale constant
const { keyHeight, spacing } = computeKeyMetrics(height, rows.length); const fontSize = settings.keyboardFontSize ?? 18; + const typingLocale = settings.typingLanguage || "en";const usedFn = fnActive && isFnMappedKey(keyDef.key); - const typingLocale = settings.typingLanguage || "en"; const output = resolveKeyOutput(label={displayLabel( k, physicalKeyState.capsLock, shiftActive, fnActive, - settings.typingLanguage || "en", + typingLocale, )}#!/bin/bash # Description: Confirm resolveKeyOutput and displayLabel accept the new locale parameter. rg -n -B2 -A10 'function resolveKeyOutput|function displayLabel|export const resolveKeyOutput|export const displayLabel' src/lib/keyboardLayouts.tsAlso applies to: 171-177
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/keyboard/Keyboard.tsx` around lines 136 - 144, Hoist the typing-language fallback into one component-level constant alongside effectiveLayout and rows, then reuse it in handleKey and the render path instead of recomputing settings.typingLanguage || "en". Verify that resolveKeyOutput and displayLabel accept the locale parameter in the expected position and with the matching type in their definitions, updating the call sites or signatures as needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.cursor/mcp.json:
- Around line 5-8: Remove the developer-specific absolute paths from the
tauri-mcp server entry in .cursor/mcp.json, including the username and local
cargo directory. Use a portable command and project-relative tauri-mcp.toml
path, or keep the local configuration untracked and add a shareable example with
setup guidance; ensure no machine-specific absolute paths remain.
In `@README.md`:
- Line 156: Update the README architecture table entry for
docs/accessibility-requirements.md to use the description “Target users and
acceptance criteria” instead of “Personas and acceptance criteria.”
- Line 6: Update the “Platform: Windows” entry in README.md to either link to
the existing Requirements section or remove the Markdown link syntax, ensuring
it is no longer an empty destination.
- Line 45: Fix the unmatched inline Markdown code delimiter in the “Macro
builder with JSON import/export” feature entry by adding the missing closing
backtick, preserving the feature text and proper rendering of subsequent
content.
In `@src-tauri/resources/wordpacks/README.md`:
- Around line 7-13: Correct the `WordPackFile.words` example in the README by
replacing the out-of-range frequency for “the” with an i32-compatible value such
as 22761659; leave the remaining example fields unchanged.
In `@src-tauri/src/db/mod.rs`:
- Around line 914-922: Update uninstall_word_pack to execute both DELETE
statements within a single database transaction, following the transaction
pattern used by import_word_pack. Commit only after both deletions succeed so
failures roll back the entire uninstall and preserve consistency between
pack_words and installed_packs.
- Around line 826-853: Normalize the search prefix to lowercase before
constructing the LIKE pattern, and make both queries in the score-building flow
compare against lowercase word values. Update the pack_words query and the
predictions query around scores so stored-word casing is normalized
consistently, preserving the existing frequency aggregation and profile
filtering behavior.
In `@src-tauri/src/icons.rs`:
- Around line 17-22: Replace the direct fs::write call in the icon-cache flow
with an atomic temporary-file write: create a uniquely named temp file in the
cache file’s directory, write the PNG fully, then rename it to cache_file on the
same volume. Preserve the existing cache_file.is_file lookup and return
behavior, and continue returning None when extraction or cache writing fails.
In `@src-tauri/src/music.rs`:
- Around line 92-102: Update path_is_allowed to check both the canonicalized
path and the original path against the entries registered by
allow_music_read_path, so fallback raw-path authorizations remain valid when
canonicalization fails. Preserve the existing allowed-path behavior for
canonical entries.
In `@src-tauri/src/prediction/mod.rs`:
- Around line 148-152: Update download_pack to deserialize the downloaded body
with serde_json::from_str before calling fs::write, preserving the existing
invalid-JSON error context. Only write the validated word pack body to dest,
then return the parsed result without reparsing it.
- Around line 160-167: Update http_get_text to use a
ureq::AgentBuilder-configured client instead of the direct ureq::get(url).call()
path, setting both connect and overall request timeouts before issuing the
request. Preserve the existing download and response-body error messages and
Result behavior.
In `@src/components/mouse/Trackpad.tsx`:
- Around line 122-135: Update flushPendingMove so it does not clear pendingDelta
when ipcInFlight.current is true: retain the accumulated dx/dy and reschedule
the animation frame for a later retry. Ensure movement is only reset once it can
be sent, including the final onPointerUp flush, and preserve the existing
in-flight protection for IPC calls.
In `@src/components/settings/SettingsPanel.tsx`:
- Around line 220-229: Update the uninstall button rendering in SettingsPanel to
use a new wordPackUninstalling translation while removal is busy, and add that
key with appropriate text to every locale dictionary; keep wordPackInstalling
for installation states.
In `@src/i18n/fr.ts`:
- Line 314: Update the showKeyboardModeToggle French translation to use the
feminine article “la” with “bascule,” preserving the rest of the string
unchanged.
- Line 110: Translate the languageEnglish entries in src/i18n/fr.ts:110-110 and
src/i18n/it.ts:110-110 to match their locale dictionaries: use “Anglais” in
fr.ts and “Inglese” in it.ts.
In `@src/lib/music/partiture.ts`:
- Around line 84-97: Swap the return signs in chooseDisplayOctaveShift: return
-1 when delta >= 7 for high themes and return +1 when delta <= -7 for low
themes. Keep the median calculation, staff-center threshold, zero-shift
behavior, and pitchToStaffPos contract unchanged.
In `@src/stores/appStore.ts`:
- Around line 949-970: Update applySuggestion so it types only the suffix when
the suggestion matches the typed prefix case-insensitively, using a
prefix-length calculation that remains correct when case folding changes length;
otherwise, first delete the existing prefix through the confirmed Rust backspace
command and then type the full word. Verify the command name and payload against
the Rust signature before integrating it, while preserving recording and
suggestion reload behavior.
- Around line 705-744: Update applyWindowHeightRatioLive to catch and handle
rejection from invoke("cmd_apply_window_layout"). On failure, clear or restore
liveHeightRatioPreview so the rejected ratio is not treated as applied and
subsequent near-equal drag updates are retried; keep the existing in-flight
cleanup and queued-ratio flush behavior intact.
---
Outside diff comments:
In `@src-tauri/capabilities/default.json`:
- Around line 17-24: Remove the unscoped "opener:allow-open-url" entry from the
capability permissions array, preserving the scoped permission object for the
explicitly allowed ms-settings:* URL pattern.
In `@src-tauri/src/tts/winrt.rs`:
- Around line 94-119: The wait_for_playback function’s fixed 500-iteration limit
prematurely ends long utterances and clears playback tracking. Remove the
50-second cap so the loop continues until cancellation or a terminal playback
state is reported, while preserving the existing state handling and cancellation
behavior.
In `@src/App.tsx`:
- Around line 37-76: Update the initialization flow in the useEffect’s init
function to handle rejected setup calls without leaving polling disabled or
producing an unhandled rejection. Ensure the keyboard polling interval is
started even when an awaited initialization step fails, while preserving
cancellation checks and cleanup through pollId.
---
Nitpick comments:
In `@scripts/generate-wordpacks.mjs`:
- Around line 18-37: Update fetchText to track redirect depth across recursive
Location-header requests and stop following redirects once a small maximum is
reached. Reject with an appropriate error when the limit is exceeded, while
preserving the existing successful-response and non-redirect error handling.
In `@src-tauri/src/db/mod.rs`:
- Around line 855-866: Update the ranking logic around the scores collection and
ranked.sort_by so pack frequency and profile usage are tracked separately; order
predictions by profile usage descending first, then pack frequency descending,
with the existing word tie-breaker. Preserve the limit truncation and frequency
conversion behavior in the PredictionEntry mapping.
In `@src-tauri/src/icons.rs`:
- Around line 57-77: Bound the icon cache during startup by adding cleanup to
the existing icon cache initialization flow around icon_cache_dir, removing
cached files older than the chosen retention period (for example, 30 days) while
preserving current directory creation and error propagation behavior.
In `@src-tauri/src/lib.rs`:
- Around line 671-700: Tighten the bare-host branch in validate_quick_action_url
so it accepts only host-shaped targets, such as label-dot-label domains with an
optional port and path, rather than arbitrary colon-containing strings. Preserve
the existing allowed schemes and HTTPS prefixing, while rejecting inputs like
javascript:alert(1) with the existing URL scheme error.
- Around line 949-957: The synchronous cmd_install_word_pack command currently
performs blocking download and database work on the command thread. Convert it
to the established tokio::task::spawn_blocking pattern used by
cmd_pick_music_song_file and cmd_start_dictation, resolve Database from the
AppHandle inside the closure rather than capturing State across the await point,
run install_word_pack and list_word_packs there, and propagate the resulting
errors.
In `@src-tauri/src/stt/groq.rs`:
- Around line 243-253: Update the energy calculation in the capture loop around
the samples lock so buf.len() <= cursor yields zero energy instead of
continuing. Preserve the existing RMS calculation for new samples, allowing the
downstream silence and max-duration flush checks to run even when the capture
callback stops delivering samples.
In `@src-tauri/src/stt/winrt.rs`:
- Around line 151-168: The concurrent start path still performs duplicate
recognizer and microphone setup before detecting an active session. Add a
starting flag to DictationRuntime, check and set it during the initial runtime
pre-check, reject competing starts while it is set, and reliably clear it on
success and every startup error path so later starts are not blocked.
In `@src-tauri/src/tts/winrt.rs`:
- Around line 139-148: Review the `with_synthesizer` usage in `speak_text`: it
holds the shared synthesizer mutex across the blocking
`SynthesizeTextToStreamAsync(...).get()` call, serializing concurrent speech. If
concurrent speech is required, replace the shared synthesizer path with a
per-call `SpeechSynthesizer` while preserving the existing voice, volume, rate,
and error handling behavior.
In `@src/components/keyboard/Keyboard.tsx`:
- Around line 136-144: Hoist the typing-language fallback into one
component-level constant alongside effectiveLayout and rows, then reuse it in
handleKey and the render path instead of recomputing settings.typingLanguage ||
"en". Verify that resolveKeyOutput and displayLabel accept the locale parameter
in the expected position and with the matching type in their definitions,
updating the call sites or signatures as needed.
In `@src/components/settings/SettingsPanel.tsx`:
- Around line 125-127: Declare a shared type for the pack shape near the
component, then replace the repeated inline object types in the packs state and
all related invoke generics with that type. Keep its fields aligned with
WordPackInfo, including nullable version and bundled status.
In `@src/hooks/useHeadTracking.ts`:
- Around line 63-76: Update the getContext call in the track function of
useHeadTracking to request the 2D context with willReadFrequently enabled,
preserving the existing canvas creation and frame-processing logic.
In `@tauri-mcp.toml`:
- Line 4: Update the auto_discover setting in tauri-mcp.toml so automatic Tauri
app discovery is opt-in or restricted to explicitly trusted workspaces; document
the trust requirement alongside the setting and avoid enabling discovery for
every checkout by default.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ba8ff43c-265f-4fe6-b742-8c96efca670d
⛔ Files ignored due to path filters (1)
src-tauri/Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (61)
.cursor/mcp.json.github/ISSUE_TEMPLATE/feature_request.yml.github/pull_request_template.md.gitignoreCONTRIBUTING.mdREADME.mddocs/accessibility-requirements.mddocs/images/README.mdscripts/generate-wordpacks.mjssrc-tauri/Cargo.tomlsrc-tauri/capabilities/default.jsonsrc-tauri/resources/wordpacks/README.mdsrc-tauri/resources/wordpacks/en.jsonsrc-tauri/src/db/mod.rssrc-tauri/src/icons.rssrc-tauri/src/input/keyboard.rssrc-tauri/src/lib.rssrc-tauri/src/macros/mod.rssrc-tauri/src/music.rssrc-tauri/src/prediction/mod.rssrc-tauri/src/profiles/mod.rssrc-tauri/src/stt/groq.rssrc-tauri/src/stt/route.rssrc-tauri/src/stt/winrt.rssrc-tauri/src/tts/sapi.rssrc-tauri/src/tts/winrt.rssrc-tauri/tauri.conf.jsonsrc/App.tsxsrc/components/head-tracking/HeadTrackingWizard.tsxsrc/components/keyboard/Keyboard.tsxsrc/components/layout/AppShell.tsxsrc/components/mouse/NumKeypad.tsxsrc/components/mouse/Trackpad.tsxsrc/components/music/MusicLessonPanel.tsxsrc/components/music/PartitureView.tsxsrc/components/phrases/PhrasePanel.tsxsrc/components/quick-actions/QuickActionsBar.tsxsrc/components/settings/SettingsPanel.tsxsrc/hooks/useHeadTracking.tssrc/i18n/de.tssrc/i18n/el.tssrc/i18n/en.tssrc/i18n/es.tssrc/i18n/fr.tssrc/i18n/index.tssrc/i18n/it.tssrc/i18n/pt.tssrc/index.csssrc/lib/keyboardLayouts.tssrc/lib/music/partiture.tssrc/lib/music/songs.tssrc/lib/quickActionIcons.tssrc/stores/appStore.tstauri-mcp.tomlwordpacks-dist/de.jsonwordpacks-dist/el.jsonwordpacks-dist/en.jsonwordpacks-dist/es.jsonwordpacks-dist/fr.jsonwordpacks-dist/it.jsonwordpacks-dist/pt.json
| - Macro builder with JSON import/export | ||
| - Language switch key with country flag icons (follows installed Windows keyboards) | ||
| - Predictive text with offline word packs (English bundled; other languages downloadable), learns from typing, disable toggle | ||
| - `Macro builder with JSON import/export |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Fix the unmatched Markdown delimiter.
Line 45 opens an inline code span and never closes it. This can corrupt the rendering of the following feature text.
Proposed fix
- - `Macro builder with JSON import/export
+ - Macro builder with JSON import/export📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - `Macro builder with JSON import/export | |
| - Macro builder with JSON import/export |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` at line 45, Fix the unmatched inline Markdown code delimiter in
the “Macro builder with JSON import/export” feature entry by adding the missing
closing backtick, preserving the feature text and proper rendering of subsequent
content.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/i18n/it.ts (2)
333-333: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winPreserve the setting semantics in the Italian labels.
src/i18n/it.ts#L333-L333: TranslatemousePanelColoras"Colore del pannello mouse". The current text omits that the control changes a color.src/i18n/it.ts#L339-L339: TranslatebackgroundImageOpacityas"Opacità dell’immagine di sfondo"."Visibilità"describes visibility, not opacity.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/i18n/it.ts` at line 333, Update the Italian labels in src/i18n/it.ts at lines 333-333 and 339-339: change mousePanelColor to “Colore del pannello mouse” and backgroundImageOpacity to “Opacità dell’immagine di sfondo” so both labels preserve their setting semantics.
325-325: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winCorrect the Italian label for
showMouseBottomRow.
"Mostra riga trascina, precisione e scorrimento"is grammatically incorrect becausetrascinais a verb. Use"Mostra la riga di trascinamento, precisione e scorrimento"instead.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/i18n/it.ts` at line 325, Update the Italian translation value for showMouseBottomRow to use the grammatically correct “Mostra la riga di trascinamento, precisione e scorrimento” wording, leaving the translation key unchanged.src-tauri/src/lib.rs (1)
671-734: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick winLimit host-shaped quick-action targets before opening them.
validate_quick_action_urlprefixes accepted host-shaped targets withhttps://and passes the result toapp.opener().open_url(...). The bare-host allow-list accepts dotted-quad IPs such as127.0.0.1and169.254.169.254, so quick actions can open browser tabs at public-facing localhost or link-local addresses. Reject numeric-only label sets unless they are explicitly supported, or otherwise limit the trusted host format.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src-tauri/src/lib.rs` around lines 671 - 734, Update is_host_shaped_url_target, used by validate_quick_action_url, to reject dotted-quad or otherwise numeric-only host labels so localhost and link-local IP targets cannot be accepted as bare hosts. Preserve valid domain-style hostnames and their optional ports, paths, queries, and fragments.
🧹 Nitpick comments (1)
src/App.tsx (1)
65-77: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueMove the cancellation check out of the
finallyblock.
if (cancelled) return;is inside afinally; Biome’slint/correctness/noUnsafeFinallyflagsreturninfinally, andfinallyreturn semantics can also discard an exception/return fromcatch. Move the cancellation check and interval setup after thetry/catch, as shown in the proposed fix.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/App.tsx` around lines 65 - 77, Move the cancelled check and keyboard polling interval setup out of the finally block and place them after the try/catch in the surrounding effect or setup flow. Preserve the existing early return when cancelled and the interval behavior that skips hidden documents and calls pollKeyboardState, while leaving error handling in the catch unchanged.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src-tauri/src/db/mod.rs`:
- Around line 823-884: Update insert_prediction to lowercase entry.word before
storing it, then change both get_predictions queries for pack_words and
predictions to compare word directly with the lowercase pattern instead of
applying SQL LOWER(word). Preserve the existing prefix filtering, ranking, and
result behavior.
---
Outside diff comments:
In `@src-tauri/src/lib.rs`:
- Around line 671-734: Update is_host_shaped_url_target, used by
validate_quick_action_url, to reject dotted-quad or otherwise numeric-only host
labels so localhost and link-local IP targets cannot be accepted as bare hosts.
Preserve valid domain-style hostnames and their optional ports, paths, queries,
and fragments.
In `@src/i18n/it.ts`:
- Line 333: Update the Italian labels in src/i18n/it.ts at lines 333-333 and
339-339: change mousePanelColor to “Colore del pannello mouse” and
backgroundImageOpacity to “Opacità dell’immagine di sfondo” so both labels
preserve their setting semantics.
- Line 325: Update the Italian translation value for showMouseBottomRow to use
the grammatically correct “Mostra la riga di trascinamento, precisione e
scorrimento” wording, leaving the translation key unchanged.
---
Nitpick comments:
In `@src/App.tsx`:
- Around line 65-77: Move the cancelled check and keyboard polling interval
setup out of the finally block and place them after the try/catch in the
surrounding effect or setup flow. Preserve the existing early return when
cancelled and the interval behavior that skips hidden documents and calls
pollKeyboardState, while leaving error handling in the catch unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: f4a583bb-1bd5-48ef-9d78-ddc0abf26862
📒 Files selected for processing (28)
.cursor/mcp.jsonREADME.mdscripts/generate-wordpacks.mjssrc-tauri/capabilities/default.jsonsrc-tauri/resources/wordpacks/README.mdsrc-tauri/src/db/mod.rssrc-tauri/src/icons.rssrc-tauri/src/lib.rssrc-tauri/src/music.rssrc-tauri/src/prediction/mod.rssrc-tauri/src/stt/groq.rssrc-tauri/src/stt/winrt.rssrc-tauri/src/tts/winrt.rssrc/App.tsxsrc/components/keyboard/Keyboard.tsxsrc/components/mouse/Trackpad.tsxsrc/components/settings/SettingsPanel.tsxsrc/hooks/useHeadTracking.tssrc/i18n/de.tssrc/i18n/el.tssrc/i18n/en.tssrc/i18n/es.tssrc/i18n/fr.tssrc/i18n/it.tssrc/i18n/pt.tssrc/lib/music/partiture.tssrc/stores/appStore.tstauri-mcp.toml
💤 Files with no reviewable changes (1)
- src-tauri/capabilities/default.json
🚧 Files skipped from review as they are similar to previous changes (20)
- src-tauri/resources/wordpacks/README.md
- .cursor/mcp.json
- src-tauri/src/stt/groq.rs
- src/i18n/en.ts
- src/i18n/pt.ts
- src-tauri/src/icons.rs
- src-tauri/src/music.rs
- src/hooks/useHeadTracking.ts
- src-tauri/src/tts/winrt.rs
- README.md
- src/i18n/de.ts
- src/i18n/fr.ts
- scripts/generate-wordpacks.mjs
- src/components/keyboard/Keyboard.tsx
- src/i18n/es.ts
- src/components/mouse/Trackpad.tsx
- src/i18n/el.ts
- src/components/settings/SettingsPanel.tsx
- src/lib/music/partiture.ts
- src/stores/appStore.ts
…case conversions - Updated the `insert_prediction` method to store words in lowercase for consistency. - Modified SQL queries in `pack_words` and `predictions` to remove the `LOWER` function, ensuring case-sensitive matching as intended.
Summary
Commit message
Use a Conventional Commits PR title (especially when squash-merging), e.g.
feat:,fix:,chore:,docs:. Release-please uses these onmainto determine version bumps.Related issue
Persona / accessibility impact
Test plan
npm run tauri devlocallyScreenshots (if UI changed)
Summary by CodeRabbit