diff --git a/src/main/auroraEngine.ts b/src/main/auroraEngine.ts index 5cb5f49..f5ebf5c 100644 --- a/src/main/auroraEngine.ts +++ b/src/main/auroraEngine.ts @@ -555,3 +555,53 @@ export async function powerOffProjects(): Promise { } catch { /* stale project or Docker unavailable */ } })) } + +export interface RuntimeImageRefreshResult { + checkedProjects: number + refreshedProjects: number + failures: string[] +} + +export async function refreshRuntimeImages(): Promise { + const registry = await loadRegistry() + const roots = [...new Set(Object.values(registry.projects))] + const failures: string[] = [] + let refreshedProjects = 0 + + // Refresh the shared router image without replacing a currently running + // router. The new revision is used the next time it is recreated. + try { + await execFileAsync('docker', ['pull', 'traefik:v3.5'], { + env: AURORA_ENV, + maxBuffer: 16 * 1024 * 1024 + }) + } catch (error) { + failures.push(`router: ${error instanceof Error ? error.message : String(error)}`) + } + + for (const root of roots) { + try { + await access(composePath(root)) + // Pulls Node, nginx/Apache, MySQL/MariaDB/PostgreSQL, Adminer, Redis, + // Mailpit, and module-provided images. Running containers are not + // restarted, so an update cannot interrupt current work. + await execFileAsync( + 'docker', + ['compose', '-f', composePath(root), 'pull', '--ignore-buildable', '--policy', 'always'], + { cwd: root, env: AURORA_ENV, maxBuffer: 32 * 1024 * 1024 } + ) + // PHP is an Aurora-built image. --pull checks the selected php: + // base tag for a newer patch/security revision before using the cache. + await execFileAsync( + 'docker', + ['compose', '-f', composePath(root), 'build', '--pull', 'php'], + { cwd: root, env: AURORA_ENV, maxBuffer: 32 * 1024 * 1024 } + ) + refreshedProjects += 1 + } catch (error) { + failures.push(`${root}: ${error instanceof Error ? error.message : String(error)}`) + } + } + + return { checkedProjects: roots.length, refreshedProjects, failures } +} diff --git a/src/main/updater.ts b/src/main/updater.ts index 98f978d..60934a7 100644 --- a/src/main/updater.ts +++ b/src/main/updater.ts @@ -5,6 +5,7 @@ import { getModuleRegistry, installModulePackage } from './moduleRegistry' +import { refreshRuntimeImages } from './auroraEngine' function updater(): AppUpdater { // electron-updater is CommonJS; destructuring its default import keeps the @@ -43,6 +44,13 @@ export function startAutomaticUpdates(): void { }) .catch((error) => console.warn('Aurora module update check failed:', error)) + void refreshRuntimeImages() + .then(({ checkedProjects, refreshedProjects, failures }) => { + console.info(`Aurora runtime update check refreshed ${refreshedProjects}/${checkedProjects} projects`) + if (failures.length) console.warn('Some Aurora runtime images could not be refreshed:', failures) + }) + .catch((error) => console.warn('Aurora runtime update check failed:', error)) + // electron-updater needs a packaged application and release metadata. The // extracted development build intentionally skips the remote app check. if (!app.isPackaged || process.env.AURORA_DISABLE_AUTO_UPDATE === '1') return