CoolFace
Datasetpublic

basant307/AI_Governance_Project

sourceHugging Faceapache-2.0updated 2mo agoView on Hugging Face
0likes48downloads
handleAutoUpdate.ts189 linesDownload Raw Back to utils
1/**2 * @license3 * Copyright 2025 Google LLC4 * SPDX-License-Identifier: Apache-2.05 */6 7import type { UpdateObject } from '../ui/utils/updateCheck.js';8import type { LoadedSettings } from '../config/settings.js';9import { getInstallationInfo } from './installationInfo.js';10import { updateEventEmitter } from './updateEventEmitter.js';11import type { HistoryItemWithoutId } from '../ui/types.js';12import { MessageType } from '../ui/types.js';13import { spawnWrapper } from './spawnWrapper.js';14import { performStandaloneUpdate } from './standalone-update.js';15import type { spawn } from 'node:child_process';16import os from 'node:os';17 18const UPDATE_SUCCESS_MESSAGE =19  'Update successful! Please restart Qwen Code to use the new version. ' +20  'Switching model providers before restarting may not work correctly.';21const UPDATE_FAILED_MESSAGE =22  'Automatic update failed. Please try updating manually.';23 24export function handleAutoUpdate(25  info: UpdateObject | null,26  settings: LoadedSettings,27  projectRoot: string,28  spawnFn: typeof spawn = spawnWrapper,29) {30  if (!info) {31    return;32  }33 34  // enableAutoUpdate is checked in gemini.tsx before calling this function,35  // so if we get here, auto-update is enabled (or undefined, which defaults to enabled).36  const isAutoUpdateEnabled =37    settings.merged.general?.enableAutoUpdate !== false;38 39  const installationInfo = getInstallationInfo(40    projectRoot,41    isAutoUpdateEnabled,42  );43 44  let combinedMessage = info.message;45  if (installationInfo.updateMessage) {46    combinedMessage += `\n${installationInfo.updateMessage}`;47  }48 49  updateEventEmitter.emit('update-received', {50    message: combinedMessage,51  });52 53  if (54    installationInfo.isStandalone &&55    installationInfo.standaloneDir &&56    isAutoUpdateEnabled57  ) {58    performStandaloneUpdate(installationInfo.standaloneDir, info.update.latest)59      .then((result) => {60        const message =61          result === 'deferred'62            ? 'Update downloaded. It will be applied after you exit this session.'63            : 'Update successful! The new version will be used on your next run.';64        updateEventEmitter.emit('update-success', { message });65      })66      .catch((err: Error) => {67        updateEventEmitter.emit('update-failed', {68          message: `Automatic update failed: ${err.message}. Re-run the installer to update manually.`,69        });70      });71    return;72  }73 74  // Don't automatically run the update if auto-update is disabled or no update command75  if (!installationInfo.updateCommand || !isAutoUpdateEnabled) {76    return;77  }78  const isNightly = info.update.latest.includes('nightly');79 80  const updateCommand = installationInfo.updateCommand.replace(81    '@latest',82    isNightly ? '@nightly' : `@${info.update.latest}`,83  );84  const isWindows = os.platform() === 'win32';85  const shell = isWindows ? 'cmd.exe' : 'bash';86  const shellArgs = isWindows ? ['/c', updateCommand] : ['-c', updateCommand];87  const updateProcess = spawnFn(shell, shellArgs, { stdio: 'pipe' });88  let errorOutput = '';89  updateProcess.stderr.on('data', (data) => {90    errorOutput += data.toString();91  });92 93  updateProcess.on('close', (code) => {94    if (code === 0) {95      updateEventEmitter.emit('update-success', {96        message: UPDATE_SUCCESS_MESSAGE,97      });98    } else {99      updateEventEmitter.emit('update-failed', {100        message: `${UPDATE_FAILED_MESSAGE} (command: ${updateCommand}, stderr: ${errorOutput.trim()})`,101      });102    }103  });104 105  updateProcess.on('error', (err) => {106    updateEventEmitter.emit('update-failed', {107      message: `${UPDATE_FAILED_MESSAGE} (error: ${err.message})`,108    });109  });110  return updateProcess;111}112 113export function setUpdateHandler(114  addItem: (item: HistoryItemWithoutId, timestamp: number) => void,115  setUpdateInfo: (info: UpdateObject | null) => void,116  isIdleRef: { current: boolean } = { current: true },117) {118  let successfullyInstalled = false;119  const pendingNotifications: HistoryItemWithoutId[] = [];120 121  const addItemOrDefer = (item: HistoryItemWithoutId) => {122    if (isIdleRef.current) {123      addItem(item, Date.now());124    } else {125      pendingNotifications.push(item);126    }127  };128 129  const handleUpdateRecieved = (info: UpdateObject) => {130    setUpdateInfo(info);131    const savedMessage = info.message;132    setTimeout(() => {133      if (!successfullyInstalled) {134        addItemOrDefer({135          type: MessageType.INFO,136          text: savedMessage,137        });138      }139      setUpdateInfo(null);140    }, 60000);141  };142 143  const handleUpdateFailed = (data?: { message?: string }) => {144    setUpdateInfo(null);145    addItemOrDefer({146      type: MessageType.ERROR,147      text: data?.message ?? UPDATE_FAILED_MESSAGE,148    });149  };150 151  const handleUpdateSuccess = (data?: { message?: string }) => {152    successfullyInstalled = true;153    setUpdateInfo(null);154    addItemOrDefer({155      type: MessageType.INFO,156      text: data?.message ?? UPDATE_SUCCESS_MESSAGE,157    });158  };159 160  const handleUpdateInfo = (data: { message: string }) => {161    addItemOrDefer({162      type: MessageType.INFO,163      text: data.message,164    });165  };166 167  updateEventEmitter.on('update-received', handleUpdateRecieved);168  updateEventEmitter.on('update-failed', handleUpdateFailed);169  updateEventEmitter.on('update-success', handleUpdateSuccess);170  updateEventEmitter.on('update-info', handleUpdateInfo);171 172  const cleanup = () => {173    updateEventEmitter.off('update-received', handleUpdateRecieved);174    updateEventEmitter.off('update-failed', handleUpdateFailed);175    updateEventEmitter.off('update-success', handleUpdateSuccess);176    updateEventEmitter.off('update-info', handleUpdateInfo);177    pendingNotifications.length = 0;178  };179 180  const flush = () => {181    while (pendingNotifications.length > 0) {182      const item = pendingNotifications.shift()!;183      addItem(item, Date.now());184    }185  };186 187  return { cleanup, flush };188}189 
basant307/AI_Governance_Project · CoolFace