Stop wiping Comfy inputs and sibling outputs during disk cleanup.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -610,7 +610,7 @@ function fileStem(filename) {
|
|||||||
return dot > 0 ? name.slice(0, dot) : name
|
return dot > 0 ? name.slice(0, dot) : name
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeNamedFile(roots, filename, subfolders) {
|
function removeNamedFile(roots, filename, subfolders, { stemSiblings = true } = {}) {
|
||||||
const deleted = []
|
const deleted = []
|
||||||
const name = basename(String(filename || ''))
|
const name = basename(String(filename || ''))
|
||||||
if (!name) return deleted
|
if (!name) return deleted
|
||||||
@@ -622,7 +622,7 @@ function removeNamedFile(roots, filename, subfolders) {
|
|||||||
const dir = sub ? join(root, String(sub).replace(/\.\./g, '')) : root
|
const dir = sub ? join(root, String(sub).replace(/\.\./g, '')) : root
|
||||||
const exact = safeFile(root, sub, name)
|
const exact = safeFile(root, sub, name)
|
||||||
if (removeFile(exact)) deleted.push(exact)
|
if (removeFile(exact)) deleted.push(exact)
|
||||||
if (!stem || !existsSync(dir)) continue
|
if (!stemSiblings || !stem || !existsSync(dir)) continue
|
||||||
let files = []
|
let files = []
|
||||||
try { files = readdirSync(dir) } catch { continue }
|
try { files = readdirSync(dir) } catch { continue }
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
@@ -700,6 +700,7 @@ function readJson(req) {
|
|||||||
|
|
||||||
function purgeDesktopFiles(body) {
|
function purgeDesktopFiles(body) {
|
||||||
const deleted = []
|
const deleted = []
|
||||||
|
const allowSweep = body?.sweep !== false
|
||||||
const names = [
|
const names = [
|
||||||
String(body?.imageName || body?.filename || ''),
|
String(body?.imageName || body?.filename || ''),
|
||||||
...(Array.isArray(body?.imageNames) ? body.imageNames : [])
|
...(Array.isArray(body?.imageNames) ? body.imageNames : [])
|
||||||
@@ -716,7 +717,8 @@ function purgeDesktopFiles(body) {
|
|||||||
deleted.push(...removeNamedFile(
|
deleted.push(...removeNamedFile(
|
||||||
rootsForType(type),
|
rootsForType(type),
|
||||||
videoName,
|
videoName,
|
||||||
[video.subfolder, imageOut ? '' : 'video', '']
|
[video.subfolder, imageOut ? '' : 'video', ''],
|
||||||
|
{ stemSiblings: false }
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
const audio = body?.audio || null
|
const audio = body?.audio || null
|
||||||
@@ -725,7 +727,8 @@ function purgeDesktopFiles(body) {
|
|||||||
deleted.push(...removeNamedFile(
|
deleted.push(...removeNamedFile(
|
||||||
rootsForType(String(audio?.type || 'output')),
|
rootsForType(String(audio?.type || 'output')),
|
||||||
audioName,
|
audioName,
|
||||||
[audio.subfolder, 'audio', '']
|
[audio.subfolder, 'audio', ''],
|
||||||
|
{ stemSiblings: false }
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
const output = body?.output || null
|
const output = body?.output || null
|
||||||
@@ -734,10 +737,13 @@ function purgeDesktopFiles(body) {
|
|||||||
deleted.push(...removeNamedFile(
|
deleted.push(...removeNamedFile(
|
||||||
rootsForType(String(output?.type || 'output')),
|
rootsForType(String(output?.type || 'output')),
|
||||||
outputName,
|
outputName,
|
||||||
[output.subfolder, 'image', 'still', '']
|
[output.subfolder, 'image', 'still', ''],
|
||||||
|
{ stemSiblings: false }
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
deleted.push(...sweepStaleStudioOutputs(body?.sweepPrefixes, body?.sweepSubfolders, body?.sweepMaxAgeMs))
|
if (allowSweep) {
|
||||||
|
deleted.push(...sweepStaleStudioOutputs(body?.sweepPrefixes, body?.sweepSubfolders, body?.sweepMaxAgeMs))
|
||||||
|
}
|
||||||
const unique = [...new Set(deleted)]
|
const unique = [...new Set(deleted)]
|
||||||
console.log(JSON.stringify({
|
console.log(JSON.stringify({
|
||||||
src: 'comfy-host-agent',
|
src: 'comfy-host-agent',
|
||||||
@@ -747,7 +753,8 @@ function purgeDesktopFiles(body) {
|
|||||||
imageNames: names,
|
imageNames: names,
|
||||||
video: videoName || null,
|
video: videoName || null,
|
||||||
audio: audioName || null,
|
audio: audioName || null,
|
||||||
output: outputName || null
|
output: outputName || null,
|
||||||
|
sweep: allowSweep
|
||||||
}))
|
}))
|
||||||
return { ok: true, deleted: unique }
|
return { ok: true, deleted: unique }
|
||||||
}
|
}
|
||||||
@@ -857,18 +864,8 @@ const server = http.createServer(async (req, res) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
function logStartupSweep() {
|
function logStartupSweep() {
|
||||||
try {
|
// Disabled: sweeping studio outputs on agent start was deleting Comfy
|
||||||
const deleted = sweepStaleStudioOutputs()
|
// files that are still part of the generation / recover workflow.
|
||||||
if (!deleted.length) return
|
|
||||||
console.log(JSON.stringify({
|
|
||||||
src: 'comfy-host-agent',
|
|
||||||
event: 'startup-sweep',
|
|
||||||
deleted: deleted.length,
|
|
||||||
files: deleted.map((path) => basename(path))
|
|
||||||
}))
|
|
||||||
} catch (error) {
|
|
||||||
console.log(JSON.stringify({ src: 'comfy-host-agent', event: 'startup-sweep-error', error: String(error?.message || error) }))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
server.listen(port, '0.0.0.0', async () => {
|
server.listen(port, '0.0.0.0', async () => {
|
||||||
|
|||||||
+6
-10
@@ -595,6 +595,8 @@ async function purgeOnDesktop(opts: {
|
|||||||
const token = String(config.comfyControlToken || process.env.COMFY_CONTROL_TOKEN || '')
|
const token = String(config.comfyControlToken || process.env.COMFY_CONTROL_TOKEN || '')
|
||||||
if (!controlUrl) return
|
if (!controlUrl) return
|
||||||
try {
|
try {
|
||||||
|
// Exact files only. Do not sweep other MiniMax/LTX outputs or inputs —
|
||||||
|
// those are still part of the desktop workflow and recover path.
|
||||||
await fetch(`${controlUrl}/purge`, {
|
await fetch(`${controlUrl}/purge`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@@ -603,14 +605,10 @@ async function purgeOnDesktop(opts: {
|
|||||||
...(token ? { Authorization: `Bearer ${token}` } : {})
|
...(token ? { Authorization: `Bearer ${token}` } : {})
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
imageName: opts.imageName || '',
|
|
||||||
imageSubfolder: opts.imageSubfolder || '',
|
|
||||||
imageNames: (opts.extraImageNames || []).filter(Boolean),
|
|
||||||
video: opts.video || null,
|
video: opts.video || null,
|
||||||
audio: opts.audio || null,
|
audio: opts.audio || null,
|
||||||
output: opts.output || (opts.video && /\.(png|jpe?g|webp|gif)$/i.test(opts.video.filename) ? opts.video : null),
|
output: opts.output || (opts.video && /\.(png|jpe?g|webp|gif)$/i.test(opts.video.filename) ? opts.video : null),
|
||||||
sweepPrefixes: comfySweepNamePrefixes(),
|
sweep: false
|
||||||
sweepSubfolders: ['video', 'audio', 'image', 'still']
|
|
||||||
}),
|
}),
|
||||||
signal: AbortSignal.timeout(12000)
|
signal: AbortSignal.timeout(12000)
|
||||||
})
|
})
|
||||||
@@ -630,15 +628,13 @@ export async function purgeComfyArtifacts(opts: {
|
|||||||
}) {
|
}) {
|
||||||
if (!purgeComfyEnabled()) return
|
if (!purgeComfyEnabled()) return
|
||||||
await purgeOnDesktop(opts)
|
await purgeOnDesktop(opts)
|
||||||
|
// Only remove the output we already copied into the library.
|
||||||
|
// Leave Comfy input stills / identity refs on disk — shot chains and
|
||||||
|
// desktop recover still need them.
|
||||||
const files: ComfyDiskFile[] = []
|
const files: ComfyDiskFile[] = []
|
||||||
if (opts.video?.filename) files.push(opts.video)
|
if (opts.video?.filename) files.push(opts.video)
|
||||||
if (opts.audio?.filename) files.push(opts.audio)
|
if (opts.audio?.filename) files.push(opts.audio)
|
||||||
if (opts.output?.filename) files.push(opts.output)
|
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) {
|
for (const file of files) {
|
||||||
await deleteComfyHttpFile(file)
|
await deleteComfyHttpFile(file)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { AsyncLocalStorage } from 'node:async_hooks'
|
import { AsyncLocalStorage } from 'node:async_hooks'
|
||||||
import { getComfyHost, viaAgentFrontDoor, comfySweepNamePrefixes } from '~/server/utils/comfy'
|
import { getComfyHost, viaAgentFrontDoor } from '~/server/utils/comfy'
|
||||||
import { comfyJobPrefix } from '~/utils/outputNames'
|
import { comfyJobPrefix } from '~/utils/outputNames'
|
||||||
|
|
||||||
const imageHostAls = new AsyncLocalStorage<string>()
|
const imageHostAls = new AsyncLocalStorage<string>()
|
||||||
@@ -385,12 +385,8 @@ async function purgeImageOnDesktop(opts: {
|
|||||||
...(token ? { Authorization: `Bearer ${token}` } : {})
|
...(token ? { Authorization: `Bearer ${token}` } : {})
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
imageName: opts.inputName || '',
|
|
||||||
imageSubfolder: opts.inputSubfolder || '',
|
|
||||||
imageNames: (opts.extraInputNames || []).filter(Boolean),
|
|
||||||
output: opts.output || null,
|
output: opts.output || null,
|
||||||
sweepPrefixes: comfySweepNamePrefixes(),
|
sweep: false
|
||||||
sweepSubfolders: ['video', 'audio', 'image', 'still']
|
|
||||||
}),
|
}),
|
||||||
signal: AbortSignal.timeout(8000)
|
signal: AbortSignal.timeout(8000)
|
||||||
})
|
})
|
||||||
@@ -415,28 +411,10 @@ export async function purgeImageComfyArtifacts(opts: {
|
|||||||
type: opts.output.type || 'output'
|
type: opts.output.type || 'output'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (opts.inputName) {
|
|
||||||
files.push({
|
|
||||||
filename: opts.inputName,
|
|
||||||
subfolder: opts.inputSubfolder || '',
|
|
||||||
type: 'input'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
for (const name of opts.extraInputNames || []) {
|
|
||||||
if (!name || name === opts.inputName) continue
|
|
||||||
files.push({
|
|
||||||
filename: name,
|
|
||||||
subfolder: opts.inputSubfolder || '',
|
|
||||||
type: 'input'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
await deleteSidecarFile(file)
|
await deleteSidecarFile(file)
|
||||||
}
|
}
|
||||||
await purgeImageOnDesktop({
|
await purgeImageOnDesktop({
|
||||||
inputName: opts.inputName,
|
|
||||||
inputSubfolder: opts.inputSubfolder,
|
|
||||||
extraInputNames: opts.extraInputNames,
|
|
||||||
output: opts.output
|
output: opts.output
|
||||||
})
|
})
|
||||||
if (opts.promptId) {
|
if (opts.promptId) {
|
||||||
|
|||||||
Reference in New Issue
Block a user