Stop deleted LoRAs from sticking in the picker.

A cache merge that preferred the longer list was keeping removed files forever. Fresh Comfy lists now replace the cache, including shrinks, and xiagen- typos stay off AIGen like xaigen-.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-09-04 21:45:31 -05:00
co-authored by Cursor
parent d50719e1a7
commit b481c4e3ad
3 changed files with 14 additions and 22 deletions
+11 -6
View File
@@ -3923,15 +3923,20 @@ async function pollLoras() {
const left = new Set(a) const left = new Set(a)
return b.every(name => left.has(name)) return b.every(name => left.has(name))
} }
if (nextVideo.length && !sameNameSet(videoLoras.value, nextVideo)) { // A successful non-empty Comfy list always wins — including when it shrank after a delete.
videoLoras.value = nextVideo if (nextVideo.length) {
rememberLoraNames('aigen-lora-names-video', nextVideo) if (!sameNameSet(videoLoras.value, nextVideo)) {
videoLoras.value = nextVideo
rememberLoraNames('aigen-lora-names-video', nextVideo)
}
} else if (!videoLoras.value.length) { } else if (!videoLoras.value.length) {
videoLoras.value = readStoredLoraNames('aigen-lora-names-video') videoLoras.value = readStoredLoraNames('aigen-lora-names-video')
} }
if (nextImage.length && !sameNameSet(imageLoras.value, nextImage)) { if (nextImage.length) {
imageLoras.value = nextImage if (!sameNameSet(imageLoras.value, nextImage)) {
rememberLoraNames('aigen-lora-names-image', nextImage) imageLoras.value = nextImage
rememberLoraNames('aigen-lora-names-image', nextImage)
}
} else if (!imageLoras.value.length) { } else if (!imageLoras.value.length) {
imageLoras.value = readStoredLoraNames('aigen-lora-names-image') imageLoras.value = readStoredLoraNames('aigen-lora-names-image')
} }
+1 -15
View File
@@ -166,24 +166,10 @@ async function loadLoraCache(options: { fresh?: boolean } = {}): Promise<LoraCac
} }
// Comfy asleep / unreachable returns empty. Keep the last good list so the picker // Comfy asleep / unreachable returns empty. Keep the last good list so the picker
// does not vanish — but do NOT refresh `at`, or a blip freezes new folder drops out. // does not vanish — but do NOT refresh `at`, or a blip freezes new folder drops out.
// Never merge a shorter fresh list back into the old one: deletes must disappear.
if (!next.image.length && !next.video.length && cache && (cache.image.length || cache.video.length)) { if (!next.image.length && !next.video.length && cache && (cache.image.length || cache.video.length)) {
return cache return cache
} }
// Prefer the richer list when a partial reply would shrink a known catalog.
if (
cache
&& (next.image.length + next.video.length) < (cache.image.length + cache.video.length)
&& next.image.every(name => cache!.image.includes(name) || cache!.video.includes(name))
&& next.video.every(name => cache!.image.includes(name) || cache!.video.includes(name))
) {
const merged: LoraCache = {
at: Date.now(),
image: uniqueNames([...cache.image, ...next.image]),
video: uniqueNames([...cache.video, ...next.video])
}
cache = merged
return merged
}
cache = next cache = next
return next return next
})().finally(() => { })().finally(() => {
+2 -1
View File
@@ -31,7 +31,8 @@ export function loraIdentityKey(name: string) {
export function isXaigenOnlyLora(name: string) { export function isXaigenOnlyLora(name: string) {
const base = loraBasename(name) const base = loraBasename(name)
return /^xaigen/i.test(base) || /klein_snofs|snofs_krea/i.test(base) // Include the common `xiagen-` typo so those files stay off AIGen too.
return /^(xai|xia)gen/i.test(base) || /klein_snofs|snofs_krea/i.test(base)
} }
/** Pick the real Comfy filename: exact path, then same basename ignoring `xaigen-`, then suffix/contains. */ /** Pick the real Comfy filename: exact path, then same basename ignoring `xaigen-`, then suffix/contains. */