feat: self-update checker with one-click update for WebUI + Agent
Shows a blue banner when the webui or hermes-agent git repos are behind
their upstream branches. One-click 'Update Now' button does stash, pull
--ff-only, stash pop, then reloads the page.
Backend (api/updates.py):
- _check_repo(): git fetch + rev-list count with 15s timeout
- check_for_updates(): 30-min server-side cache, thread-safe, skips
Docker (no .git dir)
- apply_update(): stash (if dirty), pull --ff-only, pop, invalidate cache
Routes:
- GET /api/updates/check -- returns cached {webui, agent} with behind count
- POST /api/updates/apply -- {target: 'webui'|'agent'}
Frontend:
- Blue banner (matches reconnect-banner pattern) with 'Later' / 'Update Now'
- Non-blocking boot check via fire-and-forget .then(), once per tab session
- sessionStorage guards prevent re-checking and re-showing after dismiss
Settings:
- 'Check for updates' checkbox (default: on) -- when off, no git operations
- Removed 'Default Workspace' dropdown to keep settings panel compact
Performance:
- Server cache: git fetch at most 2x/hour regardless of client count
- sessionStorage: one check per browser tab session
- _check_in_progress flag prevents concurrent fetch storms
- Fire-and-forget: does NOT block the boot sequence
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1022,6 +1022,8 @@ async function loadSettingsPanel(){
|
||||
if(showCliCb){showCliCb.checked=!!settings.show_cli_sessions;showCliCb.addEventListener('change',_markSettingsDirty,{once:false});}
|
||||
const syncCb=$('settingsSyncInsights');
|
||||
if(syncCb){syncCb.checked=!!settings.sync_to_insights;syncCb.addEventListener('change',_markSettingsDirty,{once:false});}
|
||||
const updateCb=$('settingsCheckUpdates');
|
||||
if(updateCb){updateCb.checked=settings.check_for_updates!==false;updateCb.addEventListener('change',_markSettingsDirty,{once:false});}
|
||||
// Password field: always blank (we don't send hash back)
|
||||
const pwField=$('settingsPassword');
|
||||
if(pwField){pwField.value='';pwField.addEventListener('input',_markSettingsDirty,{once:false});}
|
||||
@@ -1055,6 +1057,7 @@ async function saveSettings(andClose){
|
||||
body.show_token_usage=showTokenUsage;
|
||||
body.show_cli_sessions=showCliSessions;
|
||||
body.sync_to_insights=!!($('settingsSyncInsights')||{}).checked;
|
||||
body.check_for_updates=!!($('settingsCheckUpdates')||{}).checked;
|
||||
// Password: only act if the field has content; blank = leave auth unchanged
|
||||
if(pw && pw.trim()){
|
||||
try{
|
||||
|
||||
Reference in New Issue
Block a user