Commit Graph
3 Commits
Author SHA1 Message Date
wangyichen aa201b1550 chore(#5499): drop redundant post-divider _applyVoiceModePref call
The success branch had two adjacent calls:

  if(typeof window._applyVoiceModePref==='function') window._applyVoiceModePref();   // pre-divider (the actual fix)
  _applyComposerFooterVisibilitySettings();
  if(typeof window._applyVoiceModePref==='function') window._applyVoiceModePref();   // post-divider (redundant)

The post-divider one ran after _applyComposerFooterVisibilitySettings,
so it couldn't affect the divider the PR was meant to fix. It looked
like a defensive double-tap, but the function is idempotent and the
pref source (localStorage) doesn't change between the two synchronous
calls — so it was just dead code that made the diff look bigger than
the actual semantic change.

Drop it. Net PR footprint is now strictly: 'use the window-qualified
name and apply once before divider recompute in both IIFE branches.'

Re-tested: 26/26 pass on test_issue4598_composer_control_visibility
+ test_issue1488_composer_voice_buttons.
2026-07-05 15:55:36 +08:00
wangyichen edce177202 fix(#5499): use window._applyVoiceModePref — bare name is closure-local
Greptile P1: _applyVoiceModePref is declared with 'function' inside the
voice-mode IIFE (line 1205) and exported to window._applyVoiceModePref
at line 1212. The bare identifier _applyVoiceModePref is closure-local
and not visible from the settings-load IIFE branches at line 2997 and
line 3056 — so `typeof _applyVoiceModePref==='function'` was always
'undefined', the guard was permanently false, and the pre-divider call
silently never fired.

This undid the entire boot-order fix: divider was still computed
against the pre-sync #btnVoiceMode visibility, so the round-2 SILENT
race the PR was meant to close remained.

Fix: use window._applyVoiceModePref in both branches, matching the
already-correct call on line 2999 (which worked only by accident —
it ran AFTER _applyComposerFooterVisibilitySettings so it had no
effect on the bug, but at least it ran).

Tests: pytest tests/test_issue4598_composer_control_visibility.py
       tests/test_issue1488_composer_voice_buttons.py — 26/26 pass.
2026-07-05 15:53:56 +08:00
wangyichen 17f2d898f3 fix: retry os.replace() on Windows WinError 5 (PermissionError)
Windows locks session JSON files briefly during antivirus scans or
browser polling, causing os.replace() to raise WinError 5
(ERROR_ACCESS_DENIED). Add _safe_replace() helper that retries with
exponential backoff (50ms to 800ms, max 5 attempts) on PermissionError.
No-op on non-Windows platforms.

Replaces all 5 os.replace() call sites in models.py:
- Session.save() (main file + backup)
- _write_session_index() (full rebuild + fast path)
- prune_session_from_index()
2026-06-29 17:53:41 +00:00