2025-06-17 08:24:07 -07:00
|
|
|
/**
|
|
|
|
|
* @license
|
|
|
|
|
* Copyright 2025 Google LLC
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*/
|
|
|
|
|
|
2025-08-26 00:04:53 +02:00
|
|
|
import type { UpdateInfo } from 'update-notifier';
|
|
|
|
|
import updateNotifier from 'update-notifier';
|
2025-06-30 20:03:16 -07:00
|
|
|
import semver from 'semver';
|
2025-06-24 17:26:50 -07:00
|
|
|
import { getPackageJson } from '../../utils/package.js';
|
2025-10-17 12:44:31 -07:00
|
|
|
import type { LoadedSettings } from '../../config/settings.js';
|
2025-06-17 08:24:07 -07:00
|
|
|
|
2025-07-29 20:11:15 -04:00
|
|
|
export const FETCH_TIMEOUT_MS = 2000;
|
|
|
|
|
|
2025-07-28 17:56:52 -07:00
|
|
|
export interface UpdateObject {
|
|
|
|
|
message: string;
|
|
|
|
|
update: UpdateInfo;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-01 20:17:32 -07:00
|
|
|
/**
|
|
|
|
|
* From a nightly and stable update, determines which is the "best" one to offer.
|
|
|
|
|
* The rule is to always prefer nightly if the base versions are the same.
|
|
|
|
|
*/
|
|
|
|
|
function getBestAvailableUpdate(
|
|
|
|
|
nightly?: UpdateInfo,
|
|
|
|
|
stable?: UpdateInfo,
|
|
|
|
|
): UpdateInfo | null {
|
|
|
|
|
if (!nightly) return stable || null;
|
|
|
|
|
if (!stable) return nightly || null;
|
|
|
|
|
|
|
|
|
|
const nightlyVer = nightly.latest;
|
|
|
|
|
const stableVer = stable.latest;
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
semver.coerce(stableVer)?.version === semver.coerce(nightlyVer)?.version
|
|
|
|
|
) {
|
|
|
|
|
return nightly;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return semver.gt(stableVer, nightlyVer) ? stable : nightly;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-17 12:44:31 -07:00
|
|
|
export async function checkForUpdates(
|
|
|
|
|
settings: LoadedSettings,
|
|
|
|
|
): Promise<UpdateObject | null> {
|
2025-06-20 00:30:30 -07:00
|
|
|
try {
|
2025-10-17 12:44:31 -07:00
|
|
|
if (settings.merged.general?.disableUpdateNag) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2025-07-18 09:44:45 +09:00
|
|
|
// Skip update check when running from source (development mode)
|
2025-08-17 12:43:21 -04:00
|
|
|
if (process.env['DEV'] === 'true') {
|
2025-07-18 09:44:45 +09:00
|
|
|
return null;
|
|
|
|
|
}
|
2025-06-24 17:26:50 -07:00
|
|
|
const packageJson = await getPackageJson();
|
|
|
|
|
if (!packageJson || !packageJson.name || !packageJson.version) {
|
2025-06-20 00:30:30 -07:00
|
|
|
return null;
|
|
|
|
|
}
|
2025-08-01 20:17:32 -07:00
|
|
|
|
|
|
|
|
const { name, version: currentVersion } = packageJson;
|
|
|
|
|
const isNightly = currentVersion.includes('nightly');
|
|
|
|
|
const createNotifier = (distTag: 'latest' | 'nightly') =>
|
|
|
|
|
updateNotifier({
|
|
|
|
|
pkg: {
|
|
|
|
|
name,
|
|
|
|
|
version: currentVersion,
|
|
|
|
|
},
|
|
|
|
|
updateCheckInterval: 0,
|
|
|
|
|
shouldNotifyInNpmScript: true,
|
|
|
|
|
distTag,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (isNightly) {
|
|
|
|
|
const [nightlyUpdateInfo, latestUpdateInfo] = await Promise.all([
|
|
|
|
|
createNotifier('nightly').fetchInfo(),
|
|
|
|
|
createNotifier('latest').fetchInfo(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const bestUpdate = getBestAvailableUpdate(
|
|
|
|
|
nightlyUpdateInfo,
|
|
|
|
|
latestUpdateInfo,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (bestUpdate && semver.gt(bestUpdate.latest, currentVersion)) {
|
|
|
|
|
const message = `A new version of Gemini CLI is available! ${currentVersion} → ${bestUpdate.latest}`;
|
|
|
|
|
return {
|
|
|
|
|
message,
|
|
|
|
|
update: { ...bestUpdate, current: currentVersion },
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const updateInfo = await createNotifier('latest').fetchInfo();
|
|
|
|
|
|
|
|
|
|
if (updateInfo && semver.gt(updateInfo.latest, currentVersion)) {
|
|
|
|
|
const message = `Gemini CLI update available! ${currentVersion} → ${updateInfo.latest}`;
|
|
|
|
|
return {
|
|
|
|
|
message,
|
|
|
|
|
update: { ...updateInfo, current: currentVersion },
|
|
|
|
|
};
|
|
|
|
|
}
|
2025-06-20 00:30:30 -07:00
|
|
|
}
|
2025-06-17 08:24:07 -07:00
|
|
|
|
2025-06-20 00:30:30 -07:00
|
|
|
return null;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.warn('Failed to check for updates: ' + e);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2025-06-17 08:24:07 -07:00
|
|
|
}
|