@amd-gaia/agent-ui 0.21.1 → 0.21.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{browser-DFw6ahKM.js → browser-B1LxEoD3.js} +1 -1
- package/dist/assets/index-BaBSHxtq.js +72 -0
- package/dist/assets/index-CGT9a3El.css +1 -0
- package/dist/index.html +3 -3
- package/package.json +1 -1
- package/preload.cjs +22 -1
- package/services/auto-updater.cjs +322 -22
- package/services/backend-installer.cjs +295 -55
- package/dist/assets/index-DRnhDSoO.css +0 -1
- package/dist/assets/index-Dj-STgr2.js +0 -72
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* Wraps `electron-updater` for the GitHub Releases auto-update flow.
|
|
8
8
|
* Implements §4 Layer 3 + §7 Phase F of docs/plans/desktop-installer.mdx.
|
|
9
|
+
* Issue #1336: adds in-app rollback to a specific previous release.
|
|
9
10
|
*
|
|
10
11
|
* Behavior:
|
|
11
12
|
* - First check 10 seconds after `init()` is called (typically from
|
|
@@ -16,12 +17,17 @@
|
|
|
16
17
|
* - On `update-downloaded`, show a native dialog: "Update ready — restart?"
|
|
17
18
|
* - Renderer integration via IPC channel `gaia:update:status`
|
|
18
19
|
* - Disabled entirely via GAIA_DISABLE_UPDATE=1 env var (CI / dev / corp)
|
|
20
|
+
* - Rollback: listReleases() → installVersion(tag) → pin persisted to
|
|
21
|
+
* ~/.gaia/update-config.json so auto-update stays paused until resumeUpdates()
|
|
19
22
|
*
|
|
20
23
|
* Exports:
|
|
21
24
|
* - init(mainWindow) → set up handlers, schedule checks
|
|
22
25
|
* - destroy() → tear down timers and IPC handlers
|
|
23
26
|
* - checkForUpdates() → manually trigger a check
|
|
24
27
|
* - getState() → returns a copy of the current state
|
|
28
|
+
* - listReleases() → fetch available releases from GitHub
|
|
29
|
+
* - installVersion(tag) → downgrade/install a specific tagged release
|
|
30
|
+
* - clearPin() → resume auto-updates (clear the version pin)
|
|
25
31
|
* - STATES → string constants for valid states
|
|
26
32
|
*
|
|
27
33
|
* Design note: `electron` and `electron-updater` are lazy-required inside
|
|
@@ -43,6 +49,20 @@ const os = require("os");
|
|
|
43
49
|
const CHECK_DELAY_MS = 10 * 1000; // First check 10s after init
|
|
44
50
|
const CHECK_INTERVAL_MS = 4 * 60 * 60 * 1000; // Subsequent checks every 4h
|
|
45
51
|
const LOG_PATH = path.join(os.homedir(), ".gaia", "electron-updater.log");
|
|
52
|
+
const UPDATE_CONFIG_PATH = path.join(os.homedir(), ".gaia", "update-config.json");
|
|
53
|
+
|
|
54
|
+
// per_page=100 is the GitHub API max for a single page; we fetch broadly so
|
|
55
|
+
// draft/prerelease/platform filtering still yields a full page of installable
|
|
56
|
+
// releases before the display cap below. >100 releases would need pagination
|
|
57
|
+
// (follow the Link rel="next" header). Not built yet.
|
|
58
|
+
const GITHUB_API_RELEASES =
|
|
59
|
+
"https://api.github.com/repos/amd/gaia/releases?per_page=100";
|
|
60
|
+
|
|
61
|
+
// The picker shows only the N most-recent installable releases (rolling back
|
|
62
|
+
// more than a few versions is rare). Older versions stay reachable via the
|
|
63
|
+
// "browse all on GitHub" link in the picker, so this display cap never makes a
|
|
64
|
+
// release unreachable.
|
|
65
|
+
const MAX_RELEASES_SHOWN = 10;
|
|
46
66
|
|
|
47
67
|
const STATES = Object.freeze({
|
|
48
68
|
IDLE: "idle",
|
|
@@ -63,6 +83,8 @@ const state = {
|
|
|
63
83
|
progress: 0,
|
|
64
84
|
releaseNotes: null,
|
|
65
85
|
error: null,
|
|
86
|
+
currentVersion: null,
|
|
87
|
+
pinnedVersion: null,
|
|
66
88
|
};
|
|
67
89
|
|
|
68
90
|
let mainWindowRef = null;
|
|
@@ -73,7 +95,7 @@ let ipcHandlersRegistered = false;
|
|
|
73
95
|
let initialized = false;
|
|
74
96
|
|
|
75
97
|
// Lazy-loaded Electron references (populated inside init()).
|
|
76
|
-
let electronApi = null; // { dialog, ipcMain }
|
|
98
|
+
let electronApi = null; // { dialog, ipcMain, app }
|
|
77
99
|
let autoUpdaterRef = null; // electron-updater's singleton
|
|
78
100
|
|
|
79
101
|
// ── Logging ──────────────────────────────────────────────────────────────────
|
|
@@ -88,7 +110,6 @@ function log(level, message, ...args) {
|
|
|
88
110
|
} catch {
|
|
89
111
|
// Non-fatal — logging must never crash the app.
|
|
90
112
|
}
|
|
91
|
-
// Also mirror to stdout so devs see it in `npm start` output.
|
|
92
113
|
try {
|
|
93
114
|
// eslint-disable-next-line no-console
|
|
94
115
|
console.log(`[auto-updater] ${level} ${message}`, ...args);
|
|
@@ -105,6 +126,34 @@ function safeStringify(value) {
|
|
|
105
126
|
}
|
|
106
127
|
}
|
|
107
128
|
|
|
129
|
+
// ── Pin persistence ───────────────────────────────────────────────────────────
|
|
130
|
+
|
|
131
|
+
function _loadPin() {
|
|
132
|
+
try {
|
|
133
|
+
if (!fs.existsSync(UPDATE_CONFIG_PATH)) return null;
|
|
134
|
+
const raw = fs.readFileSync(UPDATE_CONFIG_PATH, "utf8");
|
|
135
|
+
const cfg = JSON.parse(raw);
|
|
136
|
+
return cfg.pinnedVersion || null;
|
|
137
|
+
} catch (err) {
|
|
138
|
+
log("warn", "Failed to read version pin — treating as unpinned:", err && err.message);
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Persist the version pin. Propagates write errors to the caller so that a
|
|
145
|
+
* failed pin write can abort a rollback (AC2 must not be silently broken).
|
|
146
|
+
* Callers that can tolerate a failed write (e.g. clearPin) should catch.
|
|
147
|
+
*/
|
|
148
|
+
function _savePin(pinnedVersion) {
|
|
149
|
+
fs.mkdirSync(path.dirname(UPDATE_CONFIG_PATH), { recursive: true });
|
|
150
|
+
fs.writeFileSync(
|
|
151
|
+
UPDATE_CONFIG_PATH,
|
|
152
|
+
JSON.stringify({ pinnedVersion }, null, 2),
|
|
153
|
+
"utf8"
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
108
157
|
// ── State management ─────────────────────────────────────────────────────────
|
|
109
158
|
|
|
110
159
|
function broadcastState() {
|
|
@@ -134,6 +183,214 @@ function isDisabled() {
|
|
|
134
183
|
return process.env.GAIA_DISABLE_UPDATE === "1";
|
|
135
184
|
}
|
|
136
185
|
|
|
186
|
+
// ── Platform asset detection ─────────────────────────────────────────────────
|
|
187
|
+
|
|
188
|
+
function _platformAssetPattern() {
|
|
189
|
+
if (process.platform === "win32") return /setup\.exe$/i;
|
|
190
|
+
if (process.platform === "darwin") return /\.zip$/i;
|
|
191
|
+
// Linux: AppImage (deb is apt-managed, electron-updater can't downgrade it)
|
|
192
|
+
return /\.AppImage$/i;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function _releaseHasPlatformAsset(release) {
|
|
196
|
+
const pattern = _platformAssetPattern();
|
|
197
|
+
return (
|
|
198
|
+
Array.isArray(release.assets) &&
|
|
199
|
+
release.assets.some((a) => a && a.name && pattern.test(a.name))
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ── listReleases ──────────────────────────────────────────────────────────────
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Fetch published GitHub releases filtered for this platform.
|
|
207
|
+
*
|
|
208
|
+
* Returns an array of ReleaseInfo objects newest-first, or a plain object
|
|
209
|
+
* { error: string } if the network call fails — never an empty array that
|
|
210
|
+
* would silently mask failures.
|
|
211
|
+
*
|
|
212
|
+
* @returns {Promise<Array<ReleaseInfo> | { error: string }>}
|
|
213
|
+
*/
|
|
214
|
+
async function listReleases() {
|
|
215
|
+
const allowPrerelease = process.env.GAIA_UPDATE_PRERELEASE === "1";
|
|
216
|
+
const pinnedVersion = _loadPin();
|
|
217
|
+
|
|
218
|
+
// Get the running version — use the cached electronApi if available, else
|
|
219
|
+
// attempt a direct require (works when called after init(), and from tests
|
|
220
|
+
// where electron is mocked via moduleNameMapper).
|
|
221
|
+
let currentVersion = null;
|
|
222
|
+
if (electronApi && electronApi.app) {
|
|
223
|
+
currentVersion = electronApi.app.getVersion() || null;
|
|
224
|
+
} else {
|
|
225
|
+
try {
|
|
226
|
+
// eslint-disable-next-line global-require
|
|
227
|
+
const electron = require("electron");
|
|
228
|
+
if (electron && electron.app && electron.app.getVersion) {
|
|
229
|
+
currentVersion = electron.app.getVersion() || null;
|
|
230
|
+
}
|
|
231
|
+
} catch {
|
|
232
|
+
// ignore — currentVersion stays null
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
let releases;
|
|
237
|
+
try {
|
|
238
|
+
const resp = await fetch(GITHUB_API_RELEASES, {
|
|
239
|
+
headers: {
|
|
240
|
+
Accept: "application/vnd.github+json",
|
|
241
|
+
"User-Agent": "GAIA-Agent-UI",
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
if (!resp.ok) {
|
|
245
|
+
return {
|
|
246
|
+
error: `Couldn't reach GitHub to list releases (HTTP ${resp.status}) — check your connection; you can still download installers from the Releases page.`,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
releases = await resp.json();
|
|
250
|
+
} catch (err) {
|
|
251
|
+
return {
|
|
252
|
+
error: `Couldn't reach GitHub to list releases — check your connection; you can still download installers from the Releases page. (${
|
|
253
|
+
err && err.message
|
|
254
|
+
})`,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const result = releases
|
|
259
|
+
.filter(
|
|
260
|
+
(r) =>
|
|
261
|
+
!r.draft &&
|
|
262
|
+
(allowPrerelease || !r.prerelease) &&
|
|
263
|
+
_releaseHasPlatformAsset(r)
|
|
264
|
+
)
|
|
265
|
+
.map((r) => {
|
|
266
|
+
const tag = r.tag_name || "";
|
|
267
|
+
// Version is tag without leading 'v'
|
|
268
|
+
const version = tag.startsWith("v") ? tag.slice(1) : tag;
|
|
269
|
+
return {
|
|
270
|
+
version,
|
|
271
|
+
tag,
|
|
272
|
+
date: r.published_at || null,
|
|
273
|
+
notesUrl: r.html_url || null,
|
|
274
|
+
isCurrent: currentVersion ? version === currentVersion : false,
|
|
275
|
+
isPinned: pinnedVersion ? tag === pinnedVersion : false,
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Cap to the most-recent installable releases; older ones remain reachable
|
|
280
|
+
// via the "browse all on GitHub" link in the picker.
|
|
281
|
+
return result.slice(0, MAX_RELEASES_SHOWN);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// ── installVersion ────────────────────────────────────────────────────────────
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Download and install a specific tagged release, then prompt restart.
|
|
288
|
+
*
|
|
289
|
+
* Uses the "generic provider + per-release channel file" pattern:
|
|
290
|
+
* each GitHub release hosts its own latest*.yml which describes that exact
|
|
291
|
+
* version. Setting allowDowngrade=true + pointing setFeedURL at the release
|
|
292
|
+
* folder lets electron-updater treat it as an available update.
|
|
293
|
+
*
|
|
294
|
+
* Persists the version pin BEFORE starting the download so that even if the
|
|
295
|
+
* user dismisses the restart dialog, the pin is already in place for AC2.
|
|
296
|
+
*
|
|
297
|
+
* @param {string} tag The git tag, e.g. "v0.20.0"
|
|
298
|
+
*/
|
|
299
|
+
const TAG_RE = /^v\d+\.\d+\.\d+(-[A-Za-z0-9.]+)?$/;
|
|
300
|
+
|
|
301
|
+
async function installVersion(tag) {
|
|
302
|
+
if (!autoUpdaterRef) {
|
|
303
|
+
throw new Error("installVersion called before auto-updater was initialised");
|
|
304
|
+
}
|
|
305
|
+
if (typeof tag !== "string" || !TAG_RE.test(tag)) {
|
|
306
|
+
throw new Error(
|
|
307
|
+
`Invalid release tag "${tag}" — expected the form "vMAJOR.MINOR.PATCH" (e.g. "v0.20.0")`
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
if (checkInProgress) {
|
|
311
|
+
throw new Error(
|
|
312
|
+
"An update check is already in progress — try again in a moment."
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
log("info", `Installing version ${tag} via targeted rollback`);
|
|
317
|
+
|
|
318
|
+
// Persist pin before touching the feed/allowDowngrade so AC2 holds even if
|
|
319
|
+
// the download completes but the user dismisses the restart prompt. If the
|
|
320
|
+
// pin can't be persisted we ABORT — proceeding would let the next launch
|
|
321
|
+
// silently auto-upgrade past the rollback (no silent fallbacks).
|
|
322
|
+
try {
|
|
323
|
+
_savePin(tag);
|
|
324
|
+
} catch (err) {
|
|
325
|
+
const msg = (err && err.message) || String(err);
|
|
326
|
+
throw new Error(
|
|
327
|
+
`Failed to persist version pin — rollback aborted: ${msg}`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
setState({ pinnedVersion: tag });
|
|
331
|
+
|
|
332
|
+
checkInProgress = true;
|
|
333
|
+
try {
|
|
334
|
+
autoUpdaterRef.allowDowngrade = true;
|
|
335
|
+
autoUpdaterRef.setFeedURL({
|
|
336
|
+
provider: "generic",
|
|
337
|
+
url: `https://github.com/amd/gaia/releases/download/${tag}/`,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Known limitation: the generic/tagged feed + allowDowngrade stay set
|
|
341
|
+
// until clearPin(). While pinned, autoDownload=false (set at init) keeps
|
|
342
|
+
// the scheduled check from installing anything, but that check queries the
|
|
343
|
+
// pinned release's own feed rather than GitHub-latest — so the "newer
|
|
344
|
+
// version available, you're pinned" chip won't fire until the user resumes.
|
|
345
|
+
// Restoring the github feed in the scheduled path risks racing the still-
|
|
346
|
+
// in-flight rollback download (which outlives this checkInProgress window),
|
|
347
|
+
// so it's intentionally deferred.
|
|
348
|
+
|
|
349
|
+
// Kick off the targeted check — will fire update-available → downloads →
|
|
350
|
+
// update-downloaded → our existing dialog prompts restart.
|
|
351
|
+
await autoUpdaterRef.checkForUpdates();
|
|
352
|
+
} finally {
|
|
353
|
+
checkInProgress = false;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ── clearPin / resumeUpdates ──────────────────────────────────────────────────
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Clear the version pin and resume normal auto-updates.
|
|
361
|
+
*
|
|
362
|
+
* Restores the GitHub provider feed, sets autoDownload=true, and clears
|
|
363
|
+
* allowDowngrade so the next check is the normal forward-only flow.
|
|
364
|
+
*/
|
|
365
|
+
function clearPin() {
|
|
366
|
+
// A failed clear is non-fatal — worst case the stale pin re-pauses updates
|
|
367
|
+
// on next launch and the user can retry Resume. Don't block resume on it.
|
|
368
|
+
try {
|
|
369
|
+
_savePin(null);
|
|
370
|
+
} catch (err) {
|
|
371
|
+
log("warn", "Failed to clear pin file:", err && err.message);
|
|
372
|
+
}
|
|
373
|
+
setState({ pinnedVersion: null });
|
|
374
|
+
|
|
375
|
+
if (autoUpdaterRef) {
|
|
376
|
+
autoUpdaterRef.autoDownload = true;
|
|
377
|
+
autoUpdaterRef.allowDowngrade = false;
|
|
378
|
+
// Restore the GitHub provider (overrides any generic/tagged feed set by
|
|
379
|
+
// installVersion). Owner/repo must match electron-builder.yml publish block.
|
|
380
|
+
try {
|
|
381
|
+
autoUpdaterRef.setFeedURL({
|
|
382
|
+
provider: "github",
|
|
383
|
+
owner: "amd",
|
|
384
|
+
repo: "gaia",
|
|
385
|
+
});
|
|
386
|
+
} catch (err) {
|
|
387
|
+
log("warn", "Failed to restore GitHub feed on resume:", err && err.message);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
log("info", "Version pin cleared — auto-updates resumed");
|
|
392
|
+
}
|
|
393
|
+
|
|
137
394
|
// ── Core check ───────────────────────────────────────────────────────────────
|
|
138
395
|
|
|
139
396
|
async function checkForUpdates() {
|
|
@@ -237,6 +494,18 @@ function wireAutoUpdaterEvents() {
|
|
|
237
494
|
return;
|
|
238
495
|
}
|
|
239
496
|
try {
|
|
497
|
+
const isRollback =
|
|
498
|
+
state.pinnedVersion !== null &&
|
|
499
|
+
info &&
|
|
500
|
+
info.version;
|
|
501
|
+
const title = isRollback ? "Roll back ready" : "Update ready";
|
|
502
|
+
const message = isRollback
|
|
503
|
+
? `GAIA ${info.version} is ready to install.`
|
|
504
|
+
: `GAIA ${info && info.version ? info.version : ""} has been downloaded.`;
|
|
505
|
+
const detail = isRollback
|
|
506
|
+
? `The app will restart into v${info.version}. Your chat history will be preserved.`
|
|
507
|
+
: "Restart the app to apply the update. Your chat history will be preserved.";
|
|
508
|
+
|
|
240
509
|
const choice = await electronApi.dialog.showMessageBox(
|
|
241
510
|
mainWindowRef && !mainWindowRef.isDestroyed() ? mainWindowRef : null,
|
|
242
511
|
{
|
|
@@ -244,16 +513,13 @@ function wireAutoUpdaterEvents() {
|
|
|
244
513
|
buttons: ["Restart now", "Later"],
|
|
245
514
|
defaultId: 0,
|
|
246
515
|
cancelId: 1,
|
|
247
|
-
title
|
|
248
|
-
message
|
|
249
|
-
detail
|
|
250
|
-
"Restart the app to apply the update. Your chat history will be preserved.",
|
|
516
|
+
title,
|
|
517
|
+
message,
|
|
518
|
+
detail,
|
|
251
519
|
}
|
|
252
520
|
);
|
|
253
521
|
if (choice && choice.response === 0) {
|
|
254
522
|
log("info", "User chose to restart — calling quitAndInstall");
|
|
255
|
-
// (isSilent=false, isForceRunAfter=true) — run the installer UI on
|
|
256
|
-
// Windows and relaunch after the update is applied.
|
|
257
523
|
autoUpdaterRef.quitAndInstall(false, true);
|
|
258
524
|
} else {
|
|
259
525
|
log("info", "User deferred restart — will install on next quit");
|
|
@@ -281,21 +547,37 @@ function registerIpcHandlers() {
|
|
|
281
547
|
await checkForUpdates();
|
|
282
548
|
return getState();
|
|
283
549
|
});
|
|
550
|
+
ipcMain.handle("gaia:update:list-releases", async () => {
|
|
551
|
+
return listReleases();
|
|
552
|
+
});
|
|
553
|
+
ipcMain.handle("gaia:update:install-version", async (_event, tag) => {
|
|
554
|
+
await installVersion(tag);
|
|
555
|
+
return getState();
|
|
556
|
+
});
|
|
557
|
+
ipcMain.handle("gaia:update:resume", async () => {
|
|
558
|
+
clearPin();
|
|
559
|
+
return getState();
|
|
560
|
+
});
|
|
561
|
+
|
|
284
562
|
ipcHandlersRegistered = true;
|
|
285
563
|
}
|
|
286
564
|
|
|
287
565
|
function unregisterIpcHandlers() {
|
|
288
566
|
if (!ipcHandlersRegistered || !electronApi || !electronApi.ipcMain) return;
|
|
289
567
|
const { ipcMain } = electronApi;
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
568
|
+
const channels = [
|
|
569
|
+
"gaia:update:get-status",
|
|
570
|
+
"gaia:update:check",
|
|
571
|
+
"gaia:update:list-releases",
|
|
572
|
+
"gaia:update:install-version",
|
|
573
|
+
"gaia:update:resume",
|
|
574
|
+
];
|
|
575
|
+
for (const ch of channels) {
|
|
576
|
+
try {
|
|
577
|
+
ipcMain.removeHandler(ch);
|
|
578
|
+
} catch {
|
|
579
|
+
// ignore
|
|
580
|
+
}
|
|
299
581
|
}
|
|
300
582
|
ipcHandlersRegistered = false;
|
|
301
583
|
}
|
|
@@ -329,6 +611,14 @@ function init(mainWindow) {
|
|
|
329
611
|
return;
|
|
330
612
|
}
|
|
331
613
|
|
|
614
|
+
// Read the persisted pin before touching electron-updater so pin gating
|
|
615
|
+
// is applied to the very first autoDownload flag set below.
|
|
616
|
+
const savedPin = _loadPin();
|
|
617
|
+
if (savedPin) {
|
|
618
|
+
state.pinnedVersion = savedPin;
|
|
619
|
+
log("info", `Found persisted version pin: ${savedPin} — autoDownload will be paused`);
|
|
620
|
+
}
|
|
621
|
+
|
|
332
622
|
// Lazy-load Electron and electron-updater. Any failure here is logged
|
|
333
623
|
// and the updater stays in `idle` — we never crash the app.
|
|
334
624
|
try {
|
|
@@ -348,8 +638,16 @@ function init(mainWindow) {
|
|
|
348
638
|
electronApi = {
|
|
349
639
|
dialog: electron.dialog,
|
|
350
640
|
ipcMain: electron.ipcMain,
|
|
641
|
+
app: electron.app,
|
|
351
642
|
};
|
|
352
643
|
autoUpdaterRef = electronUpdater.autoUpdater;
|
|
644
|
+
|
|
645
|
+
// Record the running version for getState() / listReleases().
|
|
646
|
+
try {
|
|
647
|
+
state.currentVersion = electron.app.getVersion() || null;
|
|
648
|
+
} catch {
|
|
649
|
+
// ignore
|
|
650
|
+
}
|
|
353
651
|
} catch (err) {
|
|
354
652
|
log("error", "Failed to load electron-updater:", err && err.message);
|
|
355
653
|
setState({
|
|
@@ -359,15 +657,14 @@ function init(mainWindow) {
|
|
|
359
657
|
return;
|
|
360
658
|
}
|
|
361
659
|
|
|
362
|
-
// Configure electron-updater.
|
|
363
|
-
// electron-builder.yml (`publish:` block) at build time; we only set
|
|
364
|
-
// behavioral flags here.
|
|
660
|
+
// Configure electron-updater.
|
|
365
661
|
try {
|
|
366
|
-
|
|
662
|
+
// When pinned, suppress autoDownload so the scheduled forward-only check
|
|
663
|
+
// cannot silently download/install a newer version (AC2).
|
|
664
|
+
autoUpdaterRef.autoDownload = savedPin ? false : true;
|
|
367
665
|
autoUpdaterRef.autoInstallOnAppQuit = true;
|
|
368
666
|
autoUpdaterRef.disableWebInstaller = true;
|
|
369
667
|
autoUpdaterRef.allowDowngrade = false;
|
|
370
|
-
// Allow pre-releases only if explicitly opted in (for beta channels later).
|
|
371
668
|
autoUpdaterRef.allowPrerelease =
|
|
372
669
|
process.env.GAIA_UPDATE_PRERELEASE === "1";
|
|
373
670
|
|
|
@@ -433,5 +730,8 @@ module.exports = {
|
|
|
433
730
|
destroy,
|
|
434
731
|
checkForUpdates,
|
|
435
732
|
getState,
|
|
733
|
+
listReleases,
|
|
734
|
+
installVersion,
|
|
735
|
+
clearPin,
|
|
436
736
|
STATES,
|
|
437
737
|
};
|