* chore: remove 65 debug console.log statements from production code
Remove bracketed debug traces ([SFTP navigateTo], [SFTPBackend],
[ManagedSourceSync], [AutoSync], [CloudSync], [Settings], etc.)
across 16 files. These were development logging that shipped to
production, creating noise in the console.
Also clean up dead variables left behind after log removal
(hotkeyDebug, results, verification reads).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove 43 unused exports and dead type definitions
Remove export keywords from symbols that are never imported outside
their defining file. Symbols still used internally keep their
definitions; symbols not used at all are removed entirely.
Removed entirely: TerminalLine, SessionLogsSettings, KDFParams,
SyncManagerConfig, GoogleTokenResponse, OneDriveTokenResponse,
getSyncStatusColor, resolveHostTerminalAppearance,
TerminalAppearanceDefaults.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add auto-update toggle setting (closes#346)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: re-check auto-update toggle when startup timer fires
Address review feedback: the startup check effect now re-reads the
toggle from localStorage when the delayed timer fires, so toggling
off after launch cancels the pending check. Also avoids setting
hasCheckedOnStartupRef when disabled, allowing re-enable to trigger
a check without restart.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback on auto-update toggle
P1: When autoDownload=false, onUpdateAvailable no longer transitions
to 'downloading' status. Instead keeps autoDownloadStatus idle so
the manual download link surfaces correctly.
P2: Added reactive autoUpdateEnabled state (synced via storage event)
as a dependency to the startup check effect. Re-enabling the toggle
mid-session now re-triggers the deferred startup check.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address P1/P2 review feedback on auto-update toggle
P1: Main process update-available handler now checks updater.autoDownload
before setting _lastStatus to 'downloading'. When autoDownload=false,
status stays 'idle' so late-opened windows don't hydrate to a stuck
0% download state.
P2: useUpdateCheck now accepts autoUpdateEnabled as a prop from the
caller instead of relying solely on storage events (which don't fire
in the same window). SettingsPage passes settings.autoUpdateEnabled
directly, so toggling in the current window takes effect immediately.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: preserve update-available info for late-opening windows
When autoDownload is off, use status 'available' (instead of 'idle')
in the main process snapshot so late-opening windows can hydrate
version info. The renderer maps 'available' to hasUpdate=true while
keeping autoDownloadStatus='idle' for the manual download path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: re-schedule auto-check on re-enable and guard startup timer
- IPC handler now calls startAutoCheck(2000) when re-enabling so the
user gets automatic checks without restarting the app.
- startAutoCheck timer checks updater.autoDownload at fire time, so
if the renderer disables auto-update via IPC before the 5s startup
timer fires, the check is skipped.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: deduplicate auto-check scheduling and clear error on fallback success
P1: startAutoCheck now cancels any existing timer before scheduling
a new one, preventing duplicate concurrent checks from multiple
windows or re-enable toggles.
P2: checkNow fallback now clears manualCheckStatus='error' when
electron-updater successfully finds an update (res.available=true),
so the UI shows 'available' instead of a stale error state.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: only reschedule on actual re-enable and hydrate cache before toggle check
P2: Track previous autoDownload state in IPC handler so startAutoCheck
is only called on actual false→true transitions, not on every window
mount that syncs the current value.
P3: Move cache hydration (STORAGE_KEY_UPDATE_LATEST_RELEASE) before
the auto-update toggle check so cached update info is always visible
even when automatic updates are disabled.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: persist auto-update preference in main process across restarts
Read/write auto-update preference to a JSON file in userData so the
main process honors it on next launch without waiting for renderer IPC.
getAutoUpdater() now initializes autoDownload from the persisted value.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: suppress cached update toast when disabled and update IPC types
P2: Cache hydration now gates hasUpdate on autoUpdateEnabled so the
App.tsx toast doesn't fire when automatic updates are disabled.
P3: Updated global.d.ts to include 'available' in getUpdateStatus
status union and 'checking' in checkForUpdate return type.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: preserve dismissed releases, show cached updates in Settings, guard concurrent checks
P2a: Updater fallback now checks STORAGE_KEY_UPDATE_DISMISSED_VERSION
before re-surfacing a release found by electron-updater.
P2b: Cache hydration always sets hasUpdate truthfully so Settings
shows the available update. Toast suppression for disabled auto-update
moved to App.tsx (reads localStorage directly).
P3: Re-enable IPC handler checks _isChecking before scheduling
startAutoCheck to prevent concurrent electron-updater calls.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use localStorageAdapter for lint compliance, skip IPC on initial mount
P1: Replace direct localStorage access with localStorageAdapter in
App.tsx toast guard to fix no-restricted-globals lint error.
P2: Skip setAutoUpdate IPC on initial mount to prevent overwriting
the main-process preference file when renderer localStorage has been
cleared (where the default would be true).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: hydrate auto-update state from main-process preference on mount
Add getAutoUpdate IPC handler so the renderer can query the persisted
preference from auto-update-pref.json. On mount, useSettingsState
reconciles localStorage with the main-process truth, preventing the
toggle from showing 'enabled' when the user had previously disabled
it and localStorage was cleared.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Handle { checking: true } response from bridge.checkForUpdate()
separately instead of treating it as "no update" — an in-flight
check will resolve via IPC events
- Restore dismissUpdate() in "View in Settings" toast onClick so
unsupported-platform users can suppress the notification; on
supported platforms the Settings window picks up download state
via IPC events independently
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Set dismissedAutoDownloadRef when hydration skips a dismissed version
so subsequent IPC events (progress/downloaded) are also suppressed
- When GitHub API fails but electron-updater fallback finds no update,
clear manualCheckStatus from 'error' to 'up-to-date' instead of
leaving Settings stuck in error state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When checkNow's GitHub API call fails (blocked/rate-limited), still
trigger electron-updater's checkForUpdate as a fallback. This restores
the update path for environments where api.github.com is unreachable
but the updater feed is still accessible.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove STORAGE_KEY_UPDATE_LAST_CHECK write from onUpdateNotAvailable
handler — it would prevent the GitHub API fallback from running on app
restart, hiding releases that exist on GitHub but aren't yet in the
electron-updater feed. Let performCheck write the timestamp instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Don't cancel startup GitHub API fallback when electron-updater says
not-available — the GitHub release may exist before updater feed
assets are published, and the fallback provides manual download link
- Rescheduled fallback now re-queries getUpdateStatus to avoid duplicate
notifications on very slow networks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace autoDownloadStatus==='idle' guard in progress/downloaded/error
callbacks with a dedicated dismissedAutoDownloadRef to distinguish
"dismissed version" from "not hydrated yet" in late-opening windows
- Don't clear hasUpdate on update-not-available — GitHub release may
exist even when electron-updater feed says no compatible update,
preserving the manual download fallback path
- Reset dismissedAutoDownloadRef on manual retry via checkNow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- When the startup fallback sees the main process check still in flight,
reschedule after 5s instead of permanently skipping — handles the case
where the auto-check fails silently (check-phase errors not broadcast)
- onUpdateNotAvailable: clear hasUpdate and manualCheckStatus to remove
stale "update available" state from earlier GitHub API checks, since
the updater feed is authoritative on supported platforms
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- checkNow: check dismissed version before marking status as 'available'
to prevent re-downloading a release the user explicitly skipped
- startAutoCheck: verify updater exists before setting _isChecking flag
to avoid permanent stuck state when electron-updater fails to load
- Clear _isChecking in all catch paths to prevent stuck state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add _isChecking flag in autoUpdateBridge to track whether
checkForUpdates is in flight; return sentinel when manual check
arrives during an active auto-check instead of starting a concurrent
call that electron-updater would reject
- Include isChecking in getUpdateStatus snapshot so the renderer can
query it before starting the GitHub API fallback
- Startup fallback now checks getUpdateStatus().isChecking to skip
when electron-updater is still checking on slow networks
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Store startAutoCheck timer ID so it can be cancelled; cancel it when
the renderer triggers a manual checkForUpdate to avoid concurrent
electron-updater calls that produce false errors
- Record lastCheckedAt and STORAGE_KEY_UPDATE_LAST_CHECK when
update-not-available fires so the throttle works on the common
no-update path and "Last checked" UI shows correctly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Broadcast 'update-not-available' from electron-updater to renderer so
the startup GitHub API check is cancelled when no update exists
- Cancel pending startup timeout in checkNow() to prevent racing with
electron-updater's startAutoCheck (concurrent calls cause false errors)
- Add onUpdateNotAvailable bridge event (preload + global.d.ts types)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- getUpdateStatus hydration: skip restoring download state for dismissed
versions so late-opening windows don't show dismissed release UI
- performCheck: only advance lastCheck timestamp and cache release data
on successful checks — failed checks no longer suppress re-checks for
an hour while leaving stale cached release visible
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- onUpdateAvailable: skip autoDownloadStatus→'downloading' transition when
version is dismissed, preventing download progress/ready toasts
- onUpdateAvailable: cancel pending startup GitHub API check timeout to
eliminate race where electron-updater is still checking at 8s
- onUpdateDownloadProgress/Downloaded/Error: suppress state transitions
when autoDownloadStatus is 'idle' (dismissed version background download)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Return idle instead of up-to-date for dev/invalid builds in
checkNow to avoid false positive status
- Replace stale cached release in getUpdateStatus hydration when
the snapshot reports a different version
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use semantic version comparison for cached release hydration to
avoid false positives when running a newer build than latest release
- Restore dismissUpdate() in startup toast so unsupported-platform
users can silence repeated notifications
- Remove dismissed-version check from ready-to-install toast since
dismissing availability should not block the install prompt
- Show manual download link in Settings on check errors too
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Persist latestRelease to localStorage so windows opened after the
initial check can hydrate release info without re-fetching
- Remove dismissUpdate() from "View in Settings" toast click — the
dismissed version key was preventing the later install-ready toast
- Hydrate cached release data when startup check is throttled so
Settings windows show the already-found update
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Don't treat unsupported auto-update platforms as download errors;
keep autoDownloadStatus at idle so manual download link shows
- Remove auto-check on SettingsApplicationTab mount to avoid
implicitly triggering downloads when opening Settings
- Update Application tab badge to reflect download/ready state
instead of always showing "Download Now"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace stale latestRelease when electron-updater reports a different
version than the cached GitHub API result
- Surface checkForUpdate() failures by setting autoDownloadStatus to
error instead of silently dropping them
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove hasUpdate gate from ready-to-install toast so dismissing
availability notification doesn't prevent restart prompt
- Only open releases page on platforms without auto-download
- Increase startup check delay to 8s to let electron-updater fire first
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Skip renderer's GitHub API startup check if electron-updater's
auto-download has already started, preventing duplicate toast
notifications for the same release
- Set hasUpdate in onUpdateAvailable IPC handler, checking dismissed
version so that dismissed releases don't trigger the persistent
"restart now" toast after auto-download completes
- Guard "ready to install" toast with hasUpdate check
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix autoDownloadStatusRef stale read during checkNow retry: eagerly
sync the ref when resetting error->idle so checkForUpdate() fires
- Refactor SettingsApplicationTab to accept update props instead of
creating its own useUpdateCheck instance, preventing duplicate checks
and inconsistent state between Application and System tabs
- Show startup-detected updates (hasUpdate) in System tab, not only
manualCheckStatus=available, so Linux/unsupported platforms see the
update and manual download button
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add getUpdateStatus IPC handler so windows opened after download started
can immediately reflect the current state instead of showing stale 'idle'
- Track _lastStatus in main process across all updater events
- Hydrate autoDownloadStatus on useUpdateCheck mount via getUpdateStatus()
- Fix toast race: use ref to track previous autoDownloadStatus so ready/error
toasts only fire on actual status transitions, not when unrelated callback
references change
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
performCheck returns a non-null UpdateCheckResult with error populated
on GitHub API/network failures. Extend the status derivation to treat
result.error as an error state instead of falling through to up-to-date.
P1: change checkNow return type from Promise<null> to Promise<UpdateCheckResult | null>
and return actual result so callers can read hasUpdate/latestRelease.
P2: reset autoDownloadStatus from 'error' to 'idle' when user triggers manual
check, enabling a retry path; also show Check for Updates button in error state.
- Fix 1: when manual check finds update and electron-updater hasn't started
downloading yet (autoDownloadStatus=idle), fire-and-forget checkForUpdate()
to kick off the auto-download pipeline without blocking the UI
- Fix 2: manualCheckStatus='up-to-date' now auto-resets to 'idle' after 5s
so the badge doesn't stay stale until the next check; any new check cancels
the pending timer first
- Fix 3: SettingsSystemTab shows "last checked: X min ago" below the update
section using lastCheckedAt from updateState; new i18n keys added for both
zh-CN and en locales (lastCheckedJustNow, lastCheckedMinutesAgo,
lastCheckedHoursAgo, lastCheckedPrefix)
Internal: add autoDownloadStatusRef and manualCheckResetTimeoutRef to
useUpdateCheck for reliable cross-closure state access and timer lifecycle.
checkNow was calling bridge.checkForUpdate() which invokes updater.checkForUpdates()
via IPC. startAutoCheck() in the main process already calls checkForUpdates() on a
5s timer, and if that network request is still pending, the concurrent IPC call from
checkNow hangs indefinitely, causing the UI to be stuck in "checking" state forever.
Per the original design spec, checkNow should use performCheck() (GitHub API) directly.
This is completely independent of electron-updater's internal state machine, so it
never conflicts with the background startAutoCheck(). performCheck handles isCheckingRef,
isChecking, hasUpdate, and latestRelease; checkNow only manages manualCheckStatus.
- Critical: In Linux fallback path, temporarily reset isCheckingRef before calling
performCheck so its own guard can run (was silently returning null due to double-set)
- Critical: Replace updateState.currentVersion closure in checkNow with currentVersionRef
to avoid reading stale '' version on early user click; remove from useCallback deps
- Important: Add explicit !result guard when bridge is unavailable, returning 'error'
status instead of silently falling through to 'up-to-date'
Implements automatic and manual update checking, displaying toast notifications when new versions are available or when the app is up to date. Enhances the toast utility to support clickable actions, custom labels, and improved accessibility. Updates UI to surface update status more prominently and localizes new update-related messages.
Improves user awareness of available updates and provides a smoother update experience.