Delete Comfy video, image, and audio files from the desktop after they are saved to the library.

Audio never called purge, image stills used untagged names, and a locked file could abort the whole host-agent delete.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-09-03 08:30:05 -05:00
co-authored by Cursor
parent d7045c0a07
commit 110865b370
7 changed files with 209 additions and 43 deletions
+60 -14
View File
@@ -531,12 +531,59 @@ export function isOurComfyVideo(video: { filename: string; subfolder: string })
})
}
export function comfySweepNamePrefixes() {
const names = new Set(['MiniMax_H3', 'xAIGen', 'XAIgen', 'LTX23', 'AIGen', 'v2-krea', 'v2-generate'])
for (const raw of [comfyFilenamePrefix(), comfyAudioPrefix(), comfyImagePrefix()]) {
const last = raw.replace(/\/$/, '').split('/').pop()
if (last) names.add(last)
}
return [...names]
}
export function comfyStudioFileTag() {
const last = comfyFilenamePrefix().replace(/\/$/, '').split('/').pop() || ''
if (/xaigen/i.test(last)) return 'xAIGen'
return 'AIGen'
}
export function comfyImagePrefix() {
const config = useRuntimeConfig()
const explicit = String(config.comfyImagePrefix || process.env.COMFY_IMAGE_PREFIX || '').trim()
if (explicit) return explicit.replace(/\/$/, '')
return `image/${comfyStudioFileTag()}`
}
export function purgeComfyEnabled() {
return useRuntimeConfig().purgeComfyOutputs !== false
}
type ComfyDiskFile = { filename: string; subfolder?: string; type?: string }
async function deleteComfyHttpFile(file: ComfyDiskFile) {
const payload = {
filename: file.filename,
subfolder: file.subfolder || '',
type: file.type || 'output'
}
for (const path of ['/delete', '/aigen/purge']) {
try {
const res = await comfyFetch(path, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
if (res.ok) return true
} catch {
/* Comfy may not expose this route */
}
}
return false
}
async function purgeOnDesktop(opts: {
video?: { filename: string; subfolder: string; type: string }
video?: ComfyDiskFile
audio?: ComfyDiskFile
output?: ComfyDiskFile
imageName?: string
imageSubfolder?: string
extraImageNames?: string[]
@@ -558,9 +605,12 @@ async function purgeOnDesktop(opts: {
imageSubfolder: opts.imageSubfolder || '',
imageNames: (opts.extraImageNames || []).filter(Boolean),
video: opts.video || null,
output: opts.video && /\.(png|jpe?g|webp|gif)$/i.test(opts.video.filename) ? opts.video : null
audio: opts.audio || null,
output: opts.output || (opts.video && /\.(png|jpe?g|webp|gif)$/i.test(opts.video.filename) ? opts.video : null),
sweepPrefixes: comfySweepNamePrefixes(),
sweepSubfolders: ['video', 'audio', 'image', 'still']
}),
signal: AbortSignal.timeout(8000)
signal: AbortSignal.timeout(12000)
})
} catch {
// Host agent may be down; Comfy HTTP purge is the fallback.
@@ -568,7 +618,9 @@ async function purgeOnDesktop(opts: {
}
export async function purgeComfyArtifacts(opts: {
video?: { filename: string; subfolder: string; type: string }
video?: ComfyDiskFile
audio?: ComfyDiskFile
output?: ComfyDiskFile
imageName?: string
imageSubfolder?: string
extraImageNames?: string[]
@@ -576,23 +628,17 @@ export async function purgeComfyArtifacts(opts: {
}) {
if (!purgeComfyEnabled()) return
await purgeOnDesktop(opts)
const files: { filename: string; subfolder: string; type: string }[] = []
const files: ComfyDiskFile[] = []
if (opts.video?.filename) files.push(opts.video)
if (opts.audio?.filename) files.push(opts.audio)
if (opts.output?.filename) files.push(opts.output)
if (opts.imageName) files.push({ filename: opts.imageName, subfolder: opts.imageSubfolder || '', type: 'input' })
for (const name of opts.extraImageNames || []) {
if (!name || name === opts.imageName) continue
files.push({ filename: name, subfolder: opts.imageSubfolder || '', type: 'input' })
}
for (const file of files) {
try {
await comfyFetch('/aigen/purge', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(file)
})
} catch {
// Comfy may not have the purge route loaded yet; never fail the saved clip.
}
await deleteComfyHttpFile(file)
}
if (opts.promptId) {
try {