8e5045b882
Harden cockpit dismiss timing and global settings navigation in E2E helpers, tune short-chapter AI prompts for local models, fix electron-updater CJS loading, and add a 10-chapter auto-writing integration test against LM Studio. Co-authored-by: Cursor <cursoragent@cursor.com>
110 lines
3.1 KiB
TypeScript
110 lines
3.1 KiB
TypeScript
import { createRequire } from 'node:module'
|
|
import { app, BrowserWindow } from 'electron'
|
|
import type { AppUpdater } from 'electron-updater'
|
|
import { IPC } from '../../shared/ipc-channels'
|
|
|
|
const require = createRequire(import.meta.url)
|
|
let autoUpdaterRef: AppUpdater | null = null
|
|
|
|
function getAutoUpdater(): AppUpdater {
|
|
if (!autoUpdaterRef) {
|
|
const electronUpdater = require('electron-updater') as { autoUpdater: AppUpdater }
|
|
autoUpdaterRef = electronUpdater.autoUpdater
|
|
}
|
|
return autoUpdaterRef
|
|
}
|
|
|
|
export interface UpdateInfoPayload {
|
|
version: string
|
|
releaseNotes?: string
|
|
}
|
|
|
|
export interface UpdateProgressPayload {
|
|
percent: number
|
|
transferred: number
|
|
total: number
|
|
}
|
|
|
|
export class UpdateService {
|
|
private disabled: boolean
|
|
private mockVersion: string | null = null
|
|
|
|
constructor() {
|
|
if (process.env.BILIN_MOCK_UPDATE === '1') {
|
|
this.disabled = false
|
|
this.mockVersion = process.env.BILIN_MOCK_UPDATE_VERSION ?? '9.9.9'
|
|
return
|
|
}
|
|
|
|
this.disabled =
|
|
process.env.BILIN_E2E === '1' ||
|
|
!app.isPackaged ||
|
|
process.env.NODE_ENV === 'development'
|
|
|
|
const autoUpdater = getAutoUpdater()
|
|
autoUpdater.autoDownload = false
|
|
autoUpdater.autoInstallOnAppQuit = true
|
|
|
|
autoUpdater.on('update-available', (info) => {
|
|
this.broadcast(IPC.UPDATE_AVAILABLE, {
|
|
version: info.version,
|
|
releaseNotes: typeof info.releaseNotes === 'string' ? info.releaseNotes : undefined
|
|
})
|
|
})
|
|
autoUpdater.on('download-progress', (p) => {
|
|
this.broadcast(IPC.UPDATE_PROGRESS, {
|
|
percent: p.percent,
|
|
transferred: p.transferred,
|
|
total: p.total
|
|
})
|
|
})
|
|
autoUpdater.on('update-downloaded', (info) => {
|
|
this.broadcast(IPC.UPDATE_DOWNLOADED, { version: info.version })
|
|
})
|
|
autoUpdater.on('error', (err) => {
|
|
this.broadcast(IPC.UPDATE_ERROR, { message: err.message })
|
|
})
|
|
}
|
|
|
|
async check(): Promise<UpdateInfoPayload | null> {
|
|
if (this.disabled) return null
|
|
if (this.mockVersion) {
|
|
const payload = { version: this.mockVersion, releaseNotes: 'Mock update' }
|
|
this.broadcast(IPC.UPDATE_AVAILABLE, payload)
|
|
return payload
|
|
}
|
|
const result = await getAutoUpdater().checkForUpdates()
|
|
const info = result?.updateInfo
|
|
if (!info) return null
|
|
return {
|
|
version: info.version,
|
|
releaseNotes: typeof info.releaseNotes === 'string' ? info.releaseNotes : undefined
|
|
}
|
|
}
|
|
|
|
async download(): Promise<void> {
|
|
if (this.disabled) return
|
|
if (this.mockVersion) {
|
|
this.broadcast(IPC.UPDATE_PROGRESS, { percent: 50, transferred: 50, total: 100 })
|
|
this.broadcast(IPC.UPDATE_DOWNLOADED, { version: this.mockVersion })
|
|
return
|
|
}
|
|
await getAutoUpdater().downloadUpdate()
|
|
}
|
|
|
|
install(): void {
|
|
if (this.disabled || this.mockVersion) return
|
|
getAutoUpdater().quitAndInstall()
|
|
}
|
|
|
|
private broadcast(channel: string, payload: unknown): void {
|
|
try {
|
|
for (const win of BrowserWindow.getAllWindows()) {
|
|
win.webContents.send(channel, payload)
|
|
}
|
|
} catch {
|
|
/* test env */
|
|
}
|
|
}
|
|
}
|