From 6d7e76f3142d341ca0ae07b49ae7d301324c3240 Mon Sep 17 00:00:00 2001 From: Benjamin Lu Date: Wed, 19 Nov 2025 15:53:35 -0800 Subject: [PATCH 1/2] Add errors for install dir edge cases (#6733) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - show explicit validation errors when the install path lives inside the desktop app bundle or updater cache - include the new locale strings for these error prompts so the UI surfaces actionable guidance ## Testing - pnpm typecheck - pnpm lint:fix ## Notes Desktop types still need to be updated to include the new validation flags; see https://github.com/Comfy-Org/desktop/pull/1400 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6733-Add-errors-for-install-dir-edge-cases-2af6d73d3650811bada6fc7dd72ecf68) by [Unito](https://www.unito.io) --- apps/desktop-ui/package.json | 2 +- .../install/InstallLocationPicker.vue | 19 ++++--- package.json | 2 +- pnpm-lock.yaml | 55 ++++++++++++++----- pnpm-workspace.yaml | 1 + src/locales/en/main.json | 2 + 6 files changed, 57 insertions(+), 24 deletions(-) diff --git a/apps/desktop-ui/package.json b/apps/desktop-ui/package.json index 0aa47e320b..48a1348728 100644 --- a/apps/desktop-ui/package.json +++ b/apps/desktop-ui/package.json @@ -91,7 +91,7 @@ "build-storybook": "storybook build -o dist/storybook" }, "dependencies": { - "@comfyorg/comfyui-electron-types": "0.4.73-0", + "@comfyorg/comfyui-electron-types": "catalog:", "@comfyorg/shared-frontend-utils": "workspace:*", "@primevue/core": "catalog:", "@primevue/themes": "catalog:", diff --git a/apps/desktop-ui/src/components/install/InstallLocationPicker.vue b/apps/desktop-ui/src/components/install/InstallLocationPicker.vue index 6b139c1e9e..2122a136e4 100644 --- a/apps/desktop-ui/src/components/install/InstallLocationPicker.vue +++ b/apps/desktop-ui/src/components/install/InstallLocationPicker.vue @@ -115,19 +115,18 @@ import Button from 'primevue/button' import Divider from 'primevue/divider' import InputText from 'primevue/inputtext' import Message from 'primevue/message' -import { type ModelRef, computed, onMounted, ref } from 'vue' +import { computed, onMounted, ref } from 'vue' +import type { ModelRef } from 'vue' import { useI18n } from 'vue-i18n' -import MigrationPicker from '@/components/install/MigrationPicker.vue' -import MirrorItem from '@/components/install/mirror/MirrorItem.vue' -import { - PYPI_MIRROR, - PYTHON_MIRROR, - type UVMirror -} from '@/constants/uvMirrors' +import { PYPI_MIRROR, PYTHON_MIRROR } from '@/constants/uvMirrors' +import type { UVMirror } from '@/constants/uvMirrors' import { electronAPI } from '@/utils/envUtil' import { ValidationState } from '@/utils/validationUtil' +import MigrationPicker from './MigrationPicker.vue' +import MirrorItem from './mirror/MirrorItem.vue' + const { t } = useI18n() const installPath = defineModel('installPath', { required: true }) @@ -229,6 +228,10 @@ const validatePath = async (path: string | undefined) => { } if (validation.parentMissing) errors.push(t('install.parentMissing')) if (validation.isOneDrive) errors.push(t('install.isOneDrive')) + if (validation.isInsideAppInstallDir) + errors.push(t('install.insideAppInstallDir')) + if (validation.isInsideUpdaterCache) + errors.push(t('install.insideUpdaterCache')) if (validation.error) errors.push(`${t('install.unhandledError')}: ${validation.error}`) diff --git a/package.json b/package.json index b83984ddaf..0ed634c370 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "dependencies": { "@alloc/quick-lru": "catalog:", "@atlaskit/pragmatic-drag-and-drop": "^1.3.1", - "@comfyorg/comfyui-electron-types": "0.4.73-0", + "@comfyorg/comfyui-electron-types": "catalog:", "@comfyorg/design-system": "workspace:*", "@comfyorg/registry-types": "workspace:*", "@comfyorg/tailwind-utils": "workspace:*", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 292a6312fd..3484361968 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,6 +9,9 @@ catalogs: '@alloc/quick-lru': specifier: ^5.2.0 version: 5.2.0 + '@comfyorg/comfyui-electron-types': + specifier: 0.5.5 + version: 0.5.5 '@eslint/js': specifier: ^9.35.0 version: 9.35.0 @@ -306,8 +309,8 @@ importers: specifier: ^1.3.1 version: 1.3.1 '@comfyorg/comfyui-electron-types': - specifier: 0.4.73-0 - version: 0.4.73-0 + specifier: 'catalog:' + version: 0.5.5 '@comfyorg/design-system': specifier: workspace:* version: link:packages/design-system @@ -682,8 +685,8 @@ importers: apps/desktop-ui: dependencies: '@comfyorg/comfyui-electron-types': - specifier: 0.4.73-0 - version: 0.4.73-0 + specifier: 'catalog:' + version: 0.5.5 '@comfyorg/shared-frontend-utils': specifier: workspace:* version: link:../../packages/shared-frontend-utils @@ -1426,8 +1429,8 @@ packages: '@cacheable/utils@2.0.3': resolution: {integrity: sha512-m7Rce68cMHlAUjvWBy9Ru1Nmw5gU0SjGGtQDdhpe6E0xnbcvrIY0Epy//JU1VYYBUTzrG9jvgmTauULGKzOkWA==} - '@comfyorg/comfyui-electron-types@0.4.73-0': - resolution: {integrity: sha512-WlItGJQx9ZWShNG9wypx3kq+19pSig/U+s5sD2SAeEcMph4u8A/TS+lnRgdKhT58VT1uD7cMcj2SJpfdBPNWvw==} + '@comfyorg/comfyui-electron-types@0.5.5': + resolution: {integrity: sha512-f3XOXpMsALIwHakz7FekVPm4/Fh2pvJPEi8tRe8jYGBt8edsd4Mkkq31Yjs2Weem3BP7yNwbdNuSiQdP/pxJyg==} '@csstools/color-helpers@5.1.0': resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} @@ -4248,6 +4251,9 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} @@ -6788,6 +6794,11 @@ packages: engines: {node: '>= 0.4'} hasBin: true + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + restore-cursor@3.1.0: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} @@ -6883,6 +6894,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -7600,8 +7616,8 @@ packages: vue-component-type-helpers@3.1.1: resolution: {integrity: sha512-B0kHv7qX6E7+kdc5nsaqjdGZ1KwNKSUQDWGy7XkTYT7wFsOpkEyaJ1Vq79TjwrrtuLRgizrTV7PPuC4rRQo+vw==} - vue-component-type-helpers@3.1.3: - resolution: {integrity: sha512-V1dOD8XYfstOKCnXbWyEJIrhTBMwSyNjv271L1Jlx9ExpNlCSuqOs3OdWrGJ0V544zXufKbcYabi/o+gK8lyfQ==} + vue-component-type-helpers@3.1.4: + resolution: {integrity: sha512-Uws7Ew1OzTTqHW8ZVl/qLl/HB+jf08M0NdFONbVWAx0N4gMLK8yfZDgeB77hDnBmaigWWEn5qP8T9BG59jIeyQ==} vue-demi@0.14.10: resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} @@ -8770,7 +8786,7 @@ snapshots: '@cacheable/utils@2.0.3': {} - '@comfyorg/comfyui-electron-types@0.4.73-0': {} + '@comfyorg/comfyui-electron-types@0.5.5': {} '@csstools/color-helpers@5.1.0': {} @@ -10285,7 +10301,7 @@ snapshots: storybook: 9.1.6(@testing-library/dom@10.4.1)(prettier@3.6.2)(vite@5.4.19(@types/node@20.14.10)(lightningcss@1.30.1)(terser@5.39.2)) type-fest: 2.19.0 vue: 3.5.13(typescript@5.9.2) - vue-component-type-helpers: 3.1.3 + vue-component-type-helpers: 3.1.4 '@swc/helpers@0.5.17': dependencies: @@ -10657,7 +10673,7 @@ snapshots: '@types/react@19.1.9': dependencies: - csstype: 3.1.3 + csstype: 3.2.3 '@types/semver@7.7.0': {} @@ -11830,6 +11846,8 @@ snapshots: csstype@3.1.3: {} + csstype@3.2.3: {} + data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 @@ -12256,7 +12274,7 @@ snapshots: dependencies: debug: 3.2.7 is-core-module: 2.16.1 - resolve: 1.22.10 + resolve: 1.22.11 transitivePeerDependencies: - supports-color optional: true @@ -13382,7 +13400,7 @@ snapshots: acorn: 8.15.0 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - semver: 7.7.2 + semver: 7.7.3 jsonc-parser@3.2.0: {} @@ -14952,6 +14970,13 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + optional: true + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 @@ -15056,6 +15081,8 @@ snapshots: semver@7.7.2: {} + semver@7.7.3: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -15943,7 +15970,7 @@ snapshots: vue-component-type-helpers@3.1.1: {} - vue-component-type-helpers@3.1.3: {} + vue-component-type-helpers@3.1.4: {} vue-demi@0.14.10(vue@3.5.13(typescript@5.9.2)): dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index a972730cb8..7d3794b460 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,6 +4,7 @@ packages: catalog: '@alloc/quick-lru': ^5.2.0 + '@comfyorg/comfyui-electron-types': 0.5.5 '@eslint/js': ^9.35.0 '@iconify-json/lucide': ^1.1.178 '@iconify/json': ^2.2.380 diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 6e53b44bc4..2ecb73a6b1 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -478,6 +478,8 @@ "cannotWrite": "Unable to write to the selected path", "insufficientFreeSpace": "Insufficient space - minimum free space", "isOneDrive": "OneDrive is not supported. Please install ComfyUI in another location.", + "insideAppInstallDir": "This folder is inside the ComfyUI Desktop application bundle and will be deleted during updates. Choose a directory outside the install folder, such as Documents/ComfyUI.", + "insideUpdaterCache": "This folder is inside the ComfyUI updater cache, which is cleared on every update. Select a different location for your data.", "nonDefaultDrive": "Please install ComfyUI on your system drive (eg. C:\\). Drives with different file systems may cause unpredicable issues. Models and other files can be stored on other drives after installation.", "parentMissing": "Path does not exist - create the containing directory first", "unhandledError": "Unknown error", From 716808d8b3783f5e0ce05ba2a70cb4455865d496 Mon Sep 17 00:00:00 2001 From: Benjamin Lu Date: Wed, 19 Nov 2025 18:13:32 -0800 Subject: [PATCH 2/2] Desktop maintenance: unsafe base path warning (#6750) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surface unsafe base path validation in the desktop maintenance view and add an installation-fix auto-refresh after successful tasks. image ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-6750-Desktop-maintenance-unsafe-base-path-warning-2b06d73d36508147aeb4d19d02bbf0f0) by [Unito](https://www.unito.io) --- .../src/constants/desktopMaintenanceTasks.ts | 3 +- .../src/stores/maintenanceTaskStore.ts | 17 +- .../src/views/MaintenanceView.stories.ts | 159 ++++++++++++++++++ apps/desktop-ui/src/views/MaintenanceView.vue | 47 +++++- src/locales/en/main.json | 8 + 5 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 apps/desktop-ui/src/views/MaintenanceView.stories.ts diff --git a/apps/desktop-ui/src/constants/desktopMaintenanceTasks.ts b/apps/desktop-ui/src/constants/desktopMaintenanceTasks.ts index 082a62045c..9f81ab394e 100644 --- a/apps/desktop-ui/src/constants/desktopMaintenanceTasks.ts +++ b/apps/desktop-ui/src/constants/desktopMaintenanceTasks.ts @@ -16,7 +16,8 @@ export const DESKTOP_MAINTENANCE_TASKS: Readonly[] = [ execute: async () => await electron.setBasePath(), name: 'Base path', shortDescription: 'Change the application base path.', - errorDescription: 'Unable to open the base path. Please select a new one.', + errorDescription: + 'The current base path is invalid or unsafe. Please select a new location.', description: 'The base path is the default location where ComfyUI stores data. It is the location for the python environment, and may also contain models, custom nodes, and other extensions.', isInstallationFix: true, diff --git a/apps/desktop-ui/src/stores/maintenanceTaskStore.ts b/apps/desktop-ui/src/stores/maintenanceTaskStore.ts index 7ce4811cf2..d3dfca18cc 100644 --- a/apps/desktop-ui/src/stores/maintenanceTaskStore.ts +++ b/apps/desktop-ui/src/stores/maintenanceTaskStore.ts @@ -85,6 +85,7 @@ export const useMaintenanceTaskStore = defineStore('maintenanceTask', () => { const electron = electronAPI() // Reactive state + const lastUpdate = ref(null) const isRefreshing = ref(false) const isRunningTerminalCommand = computed(() => tasks.value @@ -97,6 +98,13 @@ export const useMaintenanceTaskStore = defineStore('maintenanceTask', () => { .some((task) => getRunner(task)?.executing) ) + const unsafeBasePath = computed( + () => lastUpdate.value?.unsafeBasePath === true + ) + const unsafeBasePathReason = computed( + () => lastUpdate.value?.unsafeBasePathReason + ) + // Task list const tasks = ref(DESKTOP_MAINTENANCE_TASKS) @@ -123,6 +131,7 @@ export const useMaintenanceTaskStore = defineStore('maintenanceTask', () => { * @param validationUpdate Update details passed in by electron */ const processUpdate = (validationUpdate: InstallValidation) => { + lastUpdate.value = validationUpdate const update = validationUpdate as IndexedUpdate isRefreshing.value = true @@ -155,7 +164,11 @@ export const useMaintenanceTaskStore = defineStore('maintenanceTask', () => { } const execute = async (task: MaintenanceTask) => { - return getRunner(task).execute(task) + const success = await getRunner(task).execute(task) + if (success && task.isInstallationFix) { + await refreshDesktopTasks() + } + return success } return { @@ -163,6 +176,8 @@ export const useMaintenanceTaskStore = defineStore('maintenanceTask', () => { isRefreshing, isRunningTerminalCommand, isRunningInstallationFix, + unsafeBasePath, + unsafeBasePathReason, execute, getRunner, processUpdate, diff --git a/apps/desktop-ui/src/views/MaintenanceView.stories.ts b/apps/desktop-ui/src/views/MaintenanceView.stories.ts new file mode 100644 index 0000000000..5dee7106bf --- /dev/null +++ b/apps/desktop-ui/src/views/MaintenanceView.stories.ts @@ -0,0 +1,159 @@ +// eslint-disable-next-line storybook/no-renderer-packages +import type { Meta, StoryObj } from '@storybook/vue3' +import { defineAsyncComponent } from 'vue' + +type UnsafeReason = 'appInstallDir' | 'updaterCache' | 'oneDrive' | null +type ValidationIssueState = 'OK' | 'warning' | 'error' | 'skipped' + +type ValidationState = { + inProgress: boolean + installState: string + basePath?: ValidationIssueState + unsafeBasePath: boolean + unsafeBasePathReason: UnsafeReason + venvDirectory?: ValidationIssueState + pythonInterpreter?: ValidationIssueState + pythonPackages?: ValidationIssueState + uv?: ValidationIssueState + git?: ValidationIssueState + vcRedist?: ValidationIssueState + upgradePackages?: ValidationIssueState +} + +const validationState: ValidationState = { + inProgress: false, + installState: 'installed', + basePath: 'OK', + unsafeBasePath: false, + unsafeBasePathReason: null, + venvDirectory: 'OK', + pythonInterpreter: 'OK', + pythonPackages: 'OK', + uv: 'OK', + git: 'OK', + vcRedist: 'OK', + upgradePackages: 'OK' +} + +const createMockElectronAPI = () => { + const logListeners: Array<(message: string) => void> = [] + + const getValidationUpdate = () => ({ + ...validationState + }) + + return { + getPlatform: () => 'darwin', + changeTheme: (_theme: unknown) => {}, + onLogMessage: (listener: (message: string) => void) => { + logListeners.push(listener) + }, + showContextMenu: (_options: unknown) => {}, + Events: { + trackEvent: (_eventName: string, _data?: unknown) => {} + }, + Validation: { + onUpdate: (_callback: (update: unknown) => void) => {}, + async getStatus() { + return getValidationUpdate() + }, + async validateInstallation(callback: (update: unknown) => void) { + callback(getValidationUpdate()) + }, + async complete() { + // Only allow completion when the base path is safe + return !validationState.unsafeBasePath + }, + dispose: () => {} + }, + setBasePath: () => Promise.resolve(true), + reinstall: () => Promise.resolve(), + uv: { + installRequirements: () => Promise.resolve(), + clearCache: () => Promise.resolve(), + resetVenv: () => Promise.resolve() + } + } +} + +const ensureElectronAPI = () => { + const globalWindow = window as unknown as { electronAPI?: unknown } + if (!globalWindow.electronAPI) { + globalWindow.electronAPI = createMockElectronAPI() + } + + return globalWindow.electronAPI +} + +const MaintenanceView = defineAsyncComponent(async () => { + ensureElectronAPI() + const module = await import('./MaintenanceView.vue') + return module.default +}) + +const meta: Meta = { + title: 'Desktop/Views/MaintenanceView', + component: MaintenanceView, + parameters: { + layout: 'fullscreen', + backgrounds: { + default: 'dark', + values: [ + { name: 'dark', value: '#0a0a0a' }, + { name: 'neutral-900', value: '#171717' }, + { name: 'neutral-950', value: '#0a0a0a' } + ] + } + } +} + +export default meta +type Story = StoryObj + +export const Default: Story = { + name: 'All tasks OK', + render: () => ({ + components: { MaintenanceView }, + setup() { + validationState.inProgress = false + validationState.installState = 'installed' + validationState.basePath = 'OK' + validationState.unsafeBasePath = false + validationState.unsafeBasePathReason = null + validationState.venvDirectory = 'OK' + validationState.pythonInterpreter = 'OK' + validationState.pythonPackages = 'OK' + validationState.uv = 'OK' + validationState.git = 'OK' + validationState.vcRedist = 'OK' + validationState.upgradePackages = 'OK' + ensureElectronAPI() + return {} + }, + template: '' + }) +} + +export const UnsafeBasePathOneDrive: Story = { + name: 'Unsafe base path (OneDrive)', + render: () => ({ + components: { MaintenanceView }, + setup() { + validationState.inProgress = false + validationState.installState = 'installed' + validationState.basePath = 'error' + validationState.unsafeBasePath = true + validationState.unsafeBasePathReason = 'oneDrive' + validationState.venvDirectory = 'OK' + validationState.pythonInterpreter = 'OK' + validationState.pythonPackages = 'OK' + validationState.uv = 'OK' + validationState.git = 'OK' + validationState.vcRedist = 'OK' + validationState.upgradePackages = 'OK' + ensureElectronAPI() + return {} + }, + template: '' + }) +} diff --git a/apps/desktop-ui/src/views/MaintenanceView.vue b/apps/desktop-ui/src/views/MaintenanceView.vue index dbe1b269ef..433dda54da 100644 --- a/apps/desktop-ui/src/views/MaintenanceView.vue +++ b/apps/desktop-ui/src/views/MaintenanceView.vue @@ -47,6 +47,28 @@ + +
+

+ + + + {{ t('maintenance.unsafeMigration.title') }} + + + {{ unsafeReasonText }} + + + {{ t('maintenance.unsafeMigration.action') }} + + +

+
+ (filterOptions.value[0]) +const unsafeReasonText = computed(() => { + const reason = taskStore.unsafeBasePathReason + if (!reason) { + return t('maintenance.unsafeMigration.generic') + } + + if (reason === 'appInstallDir') { + return t('maintenance.unsafeMigration.appInstallDir') + } + + if (reason === 'updaterCache') { + return t('maintenance.unsafeMigration.updaterCache') + } + + if (reason === 'oneDrive') { + return t('maintenance.unsafeMigration.oneDrive') + } + + return t('maintenance.unsafeMigration.generic') +}) + /** If valid, leave the validation window. */ const completeValidation = async () => { const isValid = await electron.Validation.complete() diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 2ecb73a6b1..6bb7941cb8 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -1347,6 +1347,14 @@ "taskFailed": "Task failed to run.", "cannotContinue": "Unable to continue - errors remain", "defaultDescription": "An error occurred while running a maintenance task." + }, + "unsafeMigration": { + "title": "Unsafe install location detected", + "generic": "Your current ComfyUI base path is in a location that may be deleted or modified during updates. To avoid data loss, move it to a safe folder.", + "appInstallDir": "Your base path is inside the ComfyUI Desktop application bundle. This folder may be deleted or overwritten during updates. Choose a directory outside the install folder, such as Documents/ComfyUI.", + "updaterCache": "Your base path is inside the ComfyUI updater cache, which is cleared on each update. Choose a different location for your data.", + "oneDrive": "Your base path is on OneDrive, which can cause sync issues and accidental data loss. Choose a local folder that is not managed by OneDrive.", + "action": "Use the \"Base path\" maintenance task below to move ComfyUI to a safe location." } }, "missingModelsDialog": {