Merge branch 'Comfy-Org:main' into main

This commit is contained in:
A神 2026-04-09 11:03:47 +08:00 committed by GitHub
commit 88ff5f8a65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 36201 additions and 12283 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,7 @@ import manager_migration
from node_package import InstalledNodePackage
version_code = [3, 39]
version_code = [3, 39, 2]
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
@ -1701,6 +1701,11 @@ def write_config():
'db_mode': get_config()['db_mode'],
}
# Sanitize all string values to prevent CRLF injection attacks
for key, value in config['default'].items():
if isinstance(value, str):
config['default'][key] = value.replace('\r', '').replace('\n', '').replace('\x00', '')
directory = os.path.dirname(manager_config_path)
if not os.path.exists(directory):
os.makedirs(directory)

View File

@ -997,6 +997,15 @@ async def get_snapshot_list(request):
return web.json_response({'items': items}, content_type='application/json')
def get_safe_snapshot_path(target):
"""
Safely construct a snapshot file path, preventing path traversal attacks.
"""
if '/' in target or '\\' in target or '..' in target or '\x00' in target:
return None
return os.path.join(core.manager_snapshot_path, f"{target}.json")
@routes.get("/snapshot/remove")
async def remove_snapshot(request):
if not is_allowed_security_level('middle'):
@ -1005,8 +1014,12 @@ async def remove_snapshot(request):
try:
target = request.rel_url.query["target"]
path = get_safe_snapshot_path(target)
if path is None:
logging.error(f"[ComfyUI-Manager] Invalid snapshot target: {target}")
return web.Response(text="Invalid snapshot target", status=400)
path = os.path.join(core.manager_snapshot_path, f"{target}.json")
if os.path.exists(path):
os.remove(path)
@ -1023,8 +1036,12 @@ async def restore_snapshot(request):
try:
target = request.rel_url.query["target"]
path = get_safe_snapshot_path(target)
if path is None:
logging.error(f"[ComfyUI-Manager] Invalid snapshot target: {target}")
return web.Response(text="Invalid snapshot target", status=400)
path = os.path.join(core.manager_snapshot_path, f"{target}.json")
if os.path.exists(path):
if not os.path.exists(core.manager_startup_script_path):
os.makedirs(core.manager_startup_script_path)

View File

@ -53,6 +53,40 @@ And kill and remove /tmp/ultralytics_runner
The version 8.3.41 to 8.3.42 of the Ultralytics package you installed is compromised. Please uninstall that version and reinstall the latest version.
https://blog.comfy.org/comfyui-statement-on-the-ultralytics-crypto-miner-situation/
""",
"litellm==1.82.7": f"""
Execute following commands:
{sys.executable} -m pip uninstall litellm
The litellm PyPI package versions 1.82.7 and 1.82.8 were compromised via a supply chain attack.
Malicious code harvests SSH keys, environment variables, API keys, cloud credentials, and exfiltrates them to an attacker-controlled server.
Version 1.82.8 also installs a .pth file that executes malware on ANY Python startup, even without importing litellm.
1. Uninstall litellm immediately.
2. Assume all credentials accessible to the litellm environment are compromised.
3. Rotate all API keys, cloud credentials, SSH keys, and database passwords.
4. Check site-packages for unexpected .pth files (e.g. litellm_init.pth) and remove them.
5. Run a full malware scan.
Details: https://github.com/BerriAI/litellm/issues/24518
Advisory: PYSEC-2026-2
""",
"litellm==1.82.8": f"""
Execute following commands:
{sys.executable} -m pip uninstall litellm
The litellm PyPI package versions 1.82.7 and 1.82.8 were compromised via a supply chain attack.
Malicious code harvests SSH keys, environment variables, API keys, cloud credentials, and exfiltrates them to an attacker-controlled server.
Version 1.82.8 also installs a .pth file that executes malware on ANY Python startup, even without importing litellm.
1. Uninstall litellm immediately.
2. Assume all credentials accessible to the litellm environment are compromised.
3. Rotate all API keys, cloud credentials, SSH keys, and database passwords.
4. Check site-packages for unexpected .pth files (e.g. litellm_init.pth) and remove them.
5. Run a full malware scan.
Details: https://github.com/BerriAI/litellm/issues/24518
Advisory: PYSEC-2026-2
"""
}
@ -60,7 +94,10 @@ https://blog.comfy.org/comfyui-statement-on-the-ultralytics-crypto-miner-situati
pip_blacklist = {
"AppleBotzz": "ComfyUI_LLMVISION",
"ultralytics==8.3.41": "ultralytics==8.3.41"
"ultralytics==8.3.41": "ultralytics==8.3.41",
"ultralytics==8.3.42": "ultralytics==8.3.42",
"litellm==1.82.7": "litellm==1.82.7",
"litellm==1.82.8": "litellm==1.82.8",
}
file_blacklist = {
@ -93,10 +130,15 @@ https://blog.comfy.org/comfyui-statement-on-the-ultralytics-crypto-miner-situati
print(f"[SECURITY ALERT] custom node '{k}' is dangerous.")
detected.add(v)
installed_pip_set = set(installed_pips.strip().split('\n'))
for k, v in pip_blacklist.items():
if k in installed_pips:
detected.add(v)
break
if '==' in k:
if k in installed_pip_set:
detected.add(v)
else:
if any(line.split('==')[0] == k for line in installed_pip_set):
detected.add(v)
for k, v in file_blacklist.items():
for x in v:
@ -105,10 +147,14 @@ https://blog.comfy.org/comfyui-statement-on-the-ultralytics-crypto-miner-situati
break
if len(detected) > 0:
for line in installed_pips.split('\n'):
for line in installed_pip_set:
for k, v in pip_blacklist.items():
if k in line:
print(f"[SECURITY ALERT] '{line}' is dangerous.")
if '==' in k:
if line == k:
print(f"[SECURITY ALERT] '{line}' is dangerous.")
else:
if line.split('==')[0] == k:
print(f"[SECURITY ALERT] '{line}' is dangerous.")
print("\n########################################################################")
print(" Malware has been detected, forcibly terminating ComfyUI execution.")

View File

@ -678,7 +678,7 @@ export class ComponentBuilderDialog extends ComfyDialog {
let orig_handleFile = app.handleFile;
async function handleFile(file) {
async function handleFile(file, ...args) {
if (file.name?.endsWith(".json") || file.name?.endsWith(".pack")) {
const reader = new FileReader();
reader.onload = async () => {
@ -694,7 +694,7 @@ async function handleFile(file) {
await handle_import_components(jsonContent);
}
else {
orig_handleFile.call(app, file);
orig_handleFile.call(app, file, ...args);
}
};
reader.readAsText(file);
@ -702,7 +702,7 @@ async function handleFile(file) {
return;
}
orig_handleFile.call(app, file);
orig_handleFile.call(app, file, ...args);
}
app.handleFile = handleFile;

View File

@ -5180,6 +5180,204 @@
"size": "25.75GB"
},
{
"name": "LTX-2 19B Dev FP8",
"type": "checkpoint",
"base": "LTX-2",
"save_path": "checkpoints/LTX-2",
"description": "LTX-2 19B Dev FP8 model.",
"reference": "https://huggingface.co/Lightricks/LTX-2",
"filename": "ltx-2-19b-dev-fp8.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2/resolve/main/ltx-2-19b-dev-fp8.safetensors",
"size": "27.1GB"
},
{
"name": "LTX-2 19B Distilled FP8",
"type": "checkpoint",
"base": "LTX-2",
"save_path": "checkpoints/LTX-2",
"description": "LTX-2 19B Distilled FP8 model.",
"reference": "https://huggingface.co/Lightricks/LTX-2",
"filename": "ltx-2-19b-distilled-fp8.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2/resolve/main/ltx-2-19b-distilled-fp8.safetensors",
"size": "27.1GB"
},
{
"name": "LTX-2 19B Dev",
"type": "checkpoint",
"base": "LTX-2",
"save_path": "checkpoints/LTX-2",
"description": "LTX-2 19B Dev model.",
"reference": "https://huggingface.co/Lightricks/LTX-2",
"filename": "ltx-2-19b-dev.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2/resolve/main/ltx-2-19b-dev.safetensors",
"size": "43.3GB"
},
{
"name": "LTX-2 19B Distilled",
"type": "checkpoint",
"base": "LTX-2",
"save_path": "checkpoints/LTX-2",
"description": "LTX-2 19B Distilled model.",
"reference": "https://huggingface.co/Lightricks/LTX-2",
"filename": "ltx-2-19b-distilled.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2/resolve/main/ltx-2-19b-distilled.safetensors",
"size": "43.3GB"
},
{
"name": "LTX-2 Spatial Upscaler",
"type": "upscale",
"base": "upscale",
"save_path": "default",
"description": "Spatial upscaler model for LTX-2. This model enhances the spatial resolution of generated videos.",
"reference": "https://huggingface.co/Lightricks/LTX-2",
"filename": "ltx-2-spatial-upscaler-x2-1.0.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2/resolve/main/ltx-2-spatial-upscaler-x2-1.0.safetensors",
"size": "996MB"
},
{
"name": "LTX-2 Temporal Upscaler",
"type": "upscale",
"base": "upscale",
"save_path": "default",
"description": "Temporal upscaler model for LTX-2. This model enhances the temporal resolution of generated videos.",
"reference": "https://huggingface.co/Lightricks/LTX-2",
"filename": "ltx-2-temporal-upscaler-x2-1.0.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2/resolve/main/ltx-2-temporal-upscaler-x2-1.0.safetensors",
"size": "262MB"
},
{
"name": "LTX-2 19B Distilled LoRA",
"type": "lora",
"base": "LTX-2",
"save_path": "loras",
"description": "A LoRA adapter that transforms the standard LTX-2 19B model into a distilled version when loaded.",
"reference": "https://huggingface.co/Lightricks/LTX-2",
"filename": "ltx-2-19b-distilled-lora-384.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2/resolve/main/ltx-2-19b-distilled-lora-384.safetensors",
"size": "7.67GB"
},
{
"name": "LTX-2 19B IC LoRA - Canny Control",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for canny control on LTX-2 19B IC model. Intended for advanced edge control and guided generation.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-IC-LoRA-Canny-Control",
"filename": "ltx-2-19b-ic-lora-canny-control.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-IC-LoRA-Canny-Control/resolve/main/ltx-2-19b-ic-lora-canny-control.safetensors",
"size": "654MB"
},
{
"name": "LTX-2 19B IC LoRA - Depth Control",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for depth control on LTX-2 19B IC model. Adds depth-aware generation guidance.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-IC-LoRA-Depth-Control",
"filename": "ltx-2-19b-ic-lora-depth-control.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-IC-LoRA-Depth-Control/resolve/main/ltx-2-19b-ic-lora-depth-control.safetensors",
"size": "654MB"
},
{
"name": "LTX-2 19B IC LoRA - Detailer",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA detailer for LTX-2 19B IC. Improves fine details and sharpness in generated outputs.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-IC-LoRA-Detailer",
"filename": "ltx-2-19b-ic-lora-detailer.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-IC-LoRA-Detailer/resolve/main/ltx-2-19b-ic-lora-detailer.safetensors",
"size": "2.62GB"
},
{
"name": "LTX-2 19B IC LoRA - Pose Control",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for pose control on LTX-2 19B IC model. Enables pose-guided image/video generation.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-IC-LoRA-Pose-Control",
"filename": "ltx-2-19b-ic-lora-pose-control.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-IC-LoRA-Pose-Control/resolve/main/ltx-2-19b-ic-lora-pose-control.safetensors",
"size": "654MB"
},
{
"name": "LTX-2 19B LoRA - Camera Control Dolly In",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for dolly-in camera control with LTX-2 19B. Simulates camera moving closer to subject.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Dolly-In",
"filename": "ltx-2-19b-lora-camera-control-dolly-in.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Dolly-In/resolve/main/ltx-2-19b-lora-camera-control-dolly-in.safetensors",
"size": "327MB"
},
{
"name": "LTX-2 19B LoRA - Camera Control Dolly Left",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for dolly-left camera control with LTX-2 19B. Simulates camera moving left.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Dolly-Left",
"filename": "ltx-2-19b-lora-camera-control-dolly-left.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Dolly-Left/resolve/main/ltx-2-19b-lora-camera-control-dolly-left.safetensors",
"size": "327MB"
},
{
"name": "LTX-2 19B LoRA - Camera Control Dolly Out",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for dolly-out camera control with LTX-2 19B. Simulates camera moving away from subject.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Dolly-Out",
"filename": "ltx-2-19b-lora-camera-control-dolly-out.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Dolly-Out/resolve/main/ltx-2-19b-lora-camera-control-dolly-out.safetensors",
"size": "327MB"
},
{
"name": "LTX-2 19B LoRA - Camera Control Dolly Right",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for dolly-right camera control with LTX-2 19B. Simulates camera moving right.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Dolly-Right",
"filename": "ltx-2-19b-lora-camera-control-dolly-right.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Dolly-Right/resolve/main/ltx-2-19b-lora-camera-control-dolly-right.safetensors",
"size": "327MB"
},
{
"name": "LTX-2 19B LoRA - Camera Control Jib Down",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for jib-down camera control with LTX-2 19B. Simulates vertical camera movement downwards.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Jib-Down",
"filename": "ltx-2-19b-lora-camera-control-jib-down.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Jib-Down/resolve/main/ltx-2-19b-lora-camera-control-jib-down.safetensors",
"size": "2.21GB"
},
{
"name": "LTX-2 19B LoRA - Camera Control Jib Up",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for jib-up camera control with LTX-2 19B. Simulates vertical camera movement upwards.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Jib-Up",
"filename": "ltx-2-19b-lora-camera-control-jib-up.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Jib-Up/resolve/main/ltx-2-19b-lora-camera-control-jib-up.safetensors",
"size": "2.21GB"
},
{
"name": "LTX-2 19B LoRA - Camera Control Static",
"type": "lora",
"base": "LTX-2",
"save_path": "loras/LTX-2",
"description": "LoRA for static camera control with LTX-2 19B. Simulates stationary/static camera view.",
"reference": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Static",
"filename": "ltx-2-19b-lora-camera-control-static.safetensors",
"url": "https://huggingface.co/Lightricks/LTX-2-19b-LoRA-Camera-Control-Static/resolve/main/ltx-2-19b-lora-camera-control-static.safetensors",
"size": "2.21GB"
},
{
"name": "LTX-Video Spatial Upscaler v0.9.7",
"type": "upscale",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -371,6 +371,16 @@
],
"install_type": "git-clone",
"description": "Complete ComfyUI development toolkit with 8 professional nodes including VAE tools, universal type testing, and comprehensive debugging infrastructure."
}
},
{
"author": "ganlvtech",
"title": "ComfyUI-CustomModelPatcher",
"reference": "https://github.com/ganlvtech/ComfyUI-CustomModelPatcher",
"files": [
"https://github.com/ganlvtech/ComfyUI-CustomModelPatcher"
],
"install_type": "git-clone",
"description": "Demonstrates GPU memory management techniques for external models like onnxruntime and InsightFace in ComfyUI by pre-allocating VRAM. (Description by CC)"
}
]
}

View File

@ -370,10 +370,13 @@ try:
pass
with std_log_lock:
if self.is_stdout:
original_stdout.flush()
else:
original_stderr.flush()
try:
if self.is_stdout:
original_stdout.flush()
else:
original_stderr.flush()
except (OSError, ValueError):
pass
def close(self):
self.flush()

View File

@ -1,13 +1,13 @@
[project]
name = "comfyui-manager"
description = "ComfyUI-Manager provides features to install and manage custom nodes for ComfyUI, as well as various functionalities to assist with ComfyUI."
version = "3.39"
version = "3.39.3"
license = { file = "LICENSE.txt" }
dependencies = ["GitPython", "PyGithub", "matrix-nio", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"]
[project.urls]
Repository = "https://github.com/ltdrdata/ComfyUI-Manager"
# Used by Comfy Registry https://comfyregistry.org
# Used by Comfy Registry https://registry.comfy.org
[tool.comfy]
PublisherId = "drltdata"

View File

@ -2,6 +2,8 @@ import ast
import re
import os
import json
import threading
from collections import defaultdict
from git import Repo
import concurrent
import datetime
@ -20,7 +22,7 @@ from pathlib import Path
from typing import Set, Dict, Optional
# Scanner version for cache invalidation
SCANNER_VERSION = "2.0.12" # Add dict comprehension + export list detection
SCANNER_VERSION = "2.0.13" # Add fallback for dynamic v3 node_id
# Cache for extract_nodes and extract_nodes_enhanced results
_extract_nodes_cache: Dict[str, Set[str]] = {}
@ -195,6 +197,82 @@ g = None
parse_cnt = 0
# Thread-safe git error state
_git_error_lock = threading.Lock()
_git_errors: defaultdict = defaultdict(list) # category -> list[{'repo': str, 'op': str, 'msg': str}]
# Ordered categories: (key, display label, compiled regex). First match wins.
# Single source of truth — add new categories here only.
_GIT_ERROR_CATEGORIES = [
('repository_not_found', 'Repository Not Found', re.compile(
r'repository\s+not\s+found|does\s+not\s+exist|\b404\b|remote:\s*repository\s+not\s+found',
re.IGNORECASE
)),
('divergent_branch', 'Divergent Branch', re.compile(
r'divergent\s+branches|need\s+to\s+specify\s+how\s+to\s+reconcile\s+divergent\s+branches',
re.IGNORECASE
)),
('auth_failed', 'Authentication Failed', re.compile(
r'authentication\s+failed|could\s+not\s+read\s+username|invalid\s+username|invalid\s+password|auth\s+failed',
re.IGNORECASE
)),
('network_error', 'Network Error', re.compile(
r'could\s+not\s+resolve\s+host|connection\s+refused|timed?\s*out|failed\s+to\s+connect|'
r'network\s+is\s+unreachable|temporary\s+failure\s+in\s+name\s+resolution',
re.IGNORECASE
)),
('merge_conflict', 'Merge Conflict', re.compile(
r'merge\s+conflict|\bCONFLICT\b|automatic\s+merge\s+failed',
re.IGNORECASE
)),
('permission_denied', 'Permission Denied', re.compile(
r'permission\s+denied|access\s+denied|operation\s+not\s+permitted|publickey',
re.IGNORECASE
)),
]
def _categorize_git_error(error_str: str) -> str:
"""Classify a git error string into a category. First match wins."""
for category, _label, pattern in _GIT_ERROR_CATEGORIES:
if pattern.search(error_str):
return category
return 'other'
def _record_git_error(repo_name: str, op: str, error: Exception) -> None:
"""Record a git error in the thread-safe collector."""
category = _categorize_git_error(str(error))
with _git_error_lock:
_git_errors[category].append({'repo': repo_name, 'op': op, 'msg': str(error)})
def _report_git_errors() -> None:
"""Print a grouped summary of git errors by category."""
if not _git_errors:
return
total = sum(len(v) for v in _git_errors.values())
print(f"\n{'='*60}")
print(f"Git Operation Errors Summary: {total} failure(s)")
print(f"{'='*60}")
for category, label, _pattern in _GIT_ERROR_CATEGORIES:
entries = _git_errors.get(category, [])
if not entries:
continue
print(f"\n[{label}] ({len(entries)} repo(s))")
for entry in entries:
print(f"{entry['repo']} ({entry['op']}): {entry['msg']}")
other_entries = _git_errors.get('other', [])
if other_entries:
print(f"\n[Other] ({len(other_entries)} repo(s))")
for entry in other_entries:
print(f"{entry['repo']} ({entry['op']}): {entry['msg']}")
print(f"{'='*60}\n")
def extract_nodes(code_text):
global parse_cnt
@ -936,6 +1014,9 @@ def extract_v3_nodes(code_text):
node_id = extract_node_id_from_schema(node)
if node_id:
nodes.add(node_id)
else:
# Fallback: use class name when node_id is dynamic/empty
nodes.add(node.name)
return nodes
@ -1157,7 +1238,7 @@ def clone_or_pull_git_repository(git_url):
repo_name = git_url.split("/")[-1]
if repo_name.endswith(".git"):
repo_name = repo_name[:-4]
repo_dir = os.path.join(temp_dir, repo_name)
if os.path.exists(repo_dir):
@ -1169,12 +1250,14 @@ def clone_or_pull_git_repository(git_url):
print(f"Pulling {repo_name}...")
except Exception as e:
print(f"Failed to pull '{repo_name}': {e}")
_record_git_error(repo_name, 'pull', e)
else:
try:
Repo.clone_from(git_url, repo_dir, recursive=True)
print(f"Cloning {repo_name}...")
except Exception as e:
print(f"Failed to clone '{repo_name}': {e}")
_record_git_error(repo_name, 'clone', e)
def update_custom_nodes(scan_only_mode=False, url_list_file=None):
@ -1325,11 +1408,18 @@ def update_custom_nodes(scan_only_mode=False, url_list_file=None):
if not skip_stat_update:
process_git_stats(git_url_titles_preemptions)
# Reset error collector before this run
with _git_error_lock:
_git_errors.clear()
# Git clone/pull for all repositories
with concurrent.futures.ThreadPoolExecutor(11) as executor:
for url, title, preemptions, node_pattern in git_url_titles_preemptions:
executor.submit(process_git_url_title, url, title, preemptions, node_pattern)
# Report any git errors grouped by category (after all workers complete)
_report_git_errors()
# .py file download (skip in scan-only mode - only process git repos)
if not scan_only_mode:
py_url_titles_and_pattern = get_py_urls_from_json('custom-node-list.json')

View File

@ -4,7 +4,7 @@ git clone https://github.com/ltdrdata/ComfyUI-Manager comfyui-manager
cd ..
python -m venv venv
source venv/bin/activate
python -m pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu121
python -m pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu130
python -m pip install -r requirements.txt
python -m pip install -r custom_nodes/comfyui-manager/requirements.txt
cd ..

View File

@ -4,7 +4,7 @@ git clone https://github.com/ltdrdata/ComfyUI-Manager comfyui-manager
cd ..
python -m venv venv
call venv/Scripts/activate
python -m pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu121
python -m pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu130
python -m pip install -r requirements.txt
python -m pip install -r custom_nodes/comfyui-manager/requirements.txt
cd ..