Merge remote-tracking branch 'origin/main' into backport/comfyui-versions-pick-latest

This commit is contained in:
Benjamin Lu 2025-12-02 16:36:39 -08:00
commit 22a5992b11
18 changed files with 3731 additions and 2987 deletions

View File

@ -5,6 +5,7 @@
![menu](https://raw.githubusercontent.com/ltdrdata/ComfyUI-extension-tutorials/refs/heads/Main/ComfyUI-Manager/images/dialog.jpg)
## NOTICE
* V3.38: **Security patch** - Manager data migrated to protected path. See [Migration Guide](docs/en/v3.38-userdata-security-migration.md).
* V3.16: Support for `uv` has been added. Set `use_uv` in `config.ini`.
* V3.10: `double-click feature` is removed
* This feature has been moved to https://github.com/ltdrdata/comfyui-connection-helper
@ -140,20 +141,27 @@ This repository provides Colab notebooks that allow you to install and use Comfy
## Paths
In `ComfyUI-Manager` V3.0 and later, configuration files and dynamically generated files are located under `<USER_DIRECTORY>/default/ComfyUI-Manager/`.
Starting from V3.38, Manager uses a protected system path for enhanced security.
* <USER_DIRECTORY>
* If executed without any options, the path defaults to ComfyUI/user.
* It can be set using --user-directory <USER_DIRECTORY>.
* <USER_DIRECTORY>
* If executed without any options, the path defaults to ComfyUI/user.
* It can be set using --user-directory <USER_DIRECTORY>.
* Basic config files: `<USER_DIRECTORY>/default/ComfyUI-Manager/config.ini`
* Configurable channel lists: `<USER_DIRECTORY>/default/ComfyUI-Manager/channels.ini`
* Configurable pip overrides: `<USER_DIRECTORY>/default/ComfyUI-Manager/pip_overrides.json`
* Configurable pip blacklist: `<USER_DIRECTORY>/default/ComfyUI-Manager/pip_blacklist.list`
* Configurable pip auto fix: `<USER_DIRECTORY>/default/ComfyUI-Manager/pip_auto_fix.list`
* Saved snapshot files: `<USER_DIRECTORY>/default/ComfyUI-Manager/snapshots`
* Startup script files: `<USER_DIRECTORY>/default/ComfyUI-Manager/startup-scripts`
* Component files: `<USER_DIRECTORY>/default/ComfyUI-Manager/components`
| ComfyUI Version | Manager Path |
|-----------------|--------------|
| v0.3.76+ (with System User API) | `<USER_DIRECTORY>/__manager/` |
| Older versions | `<USER_DIRECTORY>/default/ComfyUI-Manager/` |
* Basic config files: `config.ini`
* Configurable channel lists: `channels.list`
* Configurable pip overrides: `pip_overrides.json`
* Configurable pip blacklist: `pip_blacklist.list`
* Configurable pip auto fix: `pip_auto_fix.list`
* Saved snapshot files: `snapshots/`
* Startup script files: `startup-scripts/`
* Component files: `components/`
> **Note**: See [Migration Guide](docs/en/v3.38-userdata-security-migration.md) for upgrade details.
## `extra_model_paths.yaml` Configuration

View File

@ -37293,7 +37293,79 @@
"install_type": "git-clone",
"description": "ComfyUI custom nodes for Bokeh Diffusion - Defocus Blur Control in Text-to-Image Diffusion Models."
},
{
"author": "HAL-XP",
"title": "HALXP-Comfy",
"reference": "https://github.com/hal-xp/halxp-comfy",
"files": [
"https://github.com/hal-xp/halxp-comfy"
],
"install_type": "git-clone",
"description": "A UI suite for ComfyUI including Focus mode and layout enhancements."
},
{
"author": "BuddyBytes",
"title": "Smart Resolution Toolkit",
"reference": "https://github.com/buddy-bytes/ComfyUI-SmartResolutionToolkit",
"files": [
"https://github.com/buddy-bytes/ComfyUI-SmartResolutionToolkit"
],
"install_type": "git-clone",
"description": "Resolution picker and latent generator for ComfyUI. Select presets like HD, FullHD, 2K, 4K, 8K with aspect ratios (1:1, 9:16, 4:5, 21:9 etc.) via dropdowns. Automatically snaps width/height to latent-safe multiples of 64. Ideal for EmptyLatentImage, AnimateDiff, ControlNet, video formats, and KSampler workflows. Outputs clean INT values or ready-to-use LATENT tensor."
},
{
"author": "Bharanidharan",
"title": "iSeeBetter Node for ComfyUI",
"reference": "https://github.com/llikethat/ComfyUI-iseebetter",
"files": [
"https://github.com/llikethat/ComfyUI-iseebetter"
],
"install_type": "git-clone",
"description": "Custom Node to implement iSeeBetter upscaling method."
},
{
"author": "Pondowner857",
"title": "ComfyUI Remote Workflow Executor",
"id": "comfy_Pond_Nodes_V2",
"reference": "https://github.com/Pondowner857/comfy_Pond_Nodes_V2",
"files": [
"https://github.com/Pondowner857/comfy_Pond_Nodes_V2"
],
"install_type": "git-clone",
"description": "Remote workflow executor node - Execute workflows on remote ComfyUI servers. Supports image/text/audio/video input and output."
},
{
"author": "luxdelux7",
"title": "Forbidden Vision",
"reference": "https://github.com/luxdelux7/ComfyUI-Forbidden-Vision",
"files": [
"https://github.com/luxdelux7/ComfyUI-Forbidden-Vision"
],
"install_type": "git-clone",
"description": "Custom face detection and segmentation for ComfyUI with automatic face fixing, intelligent color grading, and iterative refinement. Custom-trained models optimized for realistic, anime, and NSFW content.",
"nodename_pattern": "ForbiddenVision"
},
{
"author": "ah-kun",
"title": "ComfyUI-FailSafe-Translate-Node",
"reference": "https://github.com/ah-kun/ComfyUI-FailSafe-Translate-Node",
"files": [
"https://github.com/ah-kun/ComfyUI-FailSafe-Translate-Node"
],
"install_type": "git-clone",
"description": "Fail-safe Google Translate prompt node for ComfyUI (retry + caching)."
},
{
"author": "Kazama-Suichiku",
"title": "ComfyUI-Meshy",
"id": "comfyui-meshy",
"reference": "https://github.com/Kazama-Suichiku/ComfyUI-Meshy",
"files": [
"https://github.com/Kazama-Suichiku/ComfyUI-Meshy"
],
"install_type": "git-clone",
"description": "ComfyUI-Meshy is a 3D generation extension based on Meshy AI API. It provides Text-to-3D and Image-to-3D capabilities within ComfyUI, allowing you to generate 3D models directly from text prompts or images. Supports multiple AI models (Meshy-4, Meshy-5, Meshy-6) with customizable topology, polygon count, and PBR settings."
},

View File

@ -0,0 +1,230 @@
# ComfyUI-Manager V3.38: Userdata Security Migration Guide
## Introduction
ComfyUI-Manager V3.38 introduces a **security patch** that migrates Manager's configuration and data to a protected system path. This change leverages ComfyUI's new System User Protection API (PR #10966) to provide enhanced security isolation.
This guide explains what happens during the migration and how to handle various situations.
---
## What Changed
### Finding Your Paths
When ComfyUI starts, it displays the full paths in the terminal:
```
** User directory: /path/to/ComfyUI/user
** ComfyUI-Manager config path: /path/to/ComfyUI/user/__manager/config.ini
```
Look for these lines in your startup log to find the exact location on your system. In this guide, paths are shown relative to the `user` directory.
### Path Migration
| Data | Legacy Path | New Path |
|------|-------------|----------|
| Configuration | `user/default/ComfyUI-Manager/` | `user/__manager/` |
| Snapshots | `user/default/ComfyUI-Manager/snapshots/` | `user/__manager/snapshots/` |
### Why This Change
In older ComfyUI versions, the `default/` directory was **unprotected** and accessible via web APIs. If you ran ComfyUI with `--listen 0.0.0.0` or similar options to allow external connections, this data **may have been tampered with** by malicious actors.
**Note:** If you only used ComfyUI locally (without `--listen` or with `--listen 127.0.0.1`), your data was not exposed to this vulnerability.
The new `__manager` path uses ComfyUI's protected system directory, which:
- **Cannot be accessed** from outside (protected by ComfyUI)
- Isolates system settings from user data
- Enables stricter security for remote access
**This is why only `config.ini` is automatically migrated** - other files (snapshots) may have been compromised and should be manually verified before copying.
---
## Automatic Migration
When you start ComfyUI with the new System User Protection API, Manager automatically handles the migration:
### Step 1: Configuration Migration
Only `config.ini` is migrated automatically.
**Important**: Snapshots are **NOT** automatically migrated. You must copy them manually if needed.
### Step 2: Security Level Check
During migration, if your security level is below `normal` (i.e., `weak` or `normal-`), it will be automatically raised to `normal`. This is a safety measure because the security level setting itself may have been tampered with in the old version.
```
======================================================================
[ComfyUI-Manager] WARNING: Security level adjusted
- Previous: 'weak' → New: 'normal'
- Raised to prevent unauthorized remote access.
======================================================================
```
If you need a lower security level, you can manually edit the config after migration.
### Step 3: Legacy Backup
Your entire legacy directory is moved to a backup location:
```
user/__manager/.legacy-manager-backup/
```
This backup is preserved until you manually delete it.
---
## Persistent Backup Notification
As long as the backup exists, Manager will remind you on **every startup**:
```
----------------------------------------------------------------------
[ComfyUI-Manager] NOTICE: Legacy backup exists
- Your old Manager data was backed up to:
/path/to/ComfyUI/user/__manager/.legacy-manager-backup
- Please verify and remove it when no longer needed.
----------------------------------------------------------------------
```
**To stop this notification**: Delete the `.legacy-manager-backup` folder inside `user/__manager/` after confirming you don't need any data from it.
---
## Recovering Old Data
### Snapshots
If you need your old snapshots, copy the contents of `.legacy-manager-backup/snapshots/` to `user/__manager/snapshots/`.
---
## Outdated ComfyUI Warning
If you're running an older version of ComfyUI without the System User Protection API, Manager will:
1. **Force security level to `strong`** - All installations are blocked
2. **Display warning message**:
```
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ComfyUI-Manager] ERROR: ComfyUI version is outdated!
- Most operations are blocked for security.
- ComfyUI update is still allowed.
- Please update ComfyUI to use Manager normally.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
```
**Solution**: Update ComfyUI to v0.3.76 or later.
---
## Security Levels
| Level | What's Allowed |
|-------|----------------|
| `strong` | ComfyUI update only. All other installations blocked. |
| `normal` | Install/update/remove registered custom nodes and models. |
| `normal-` | Above + Install via Git URL or pip (localhost only). |
| `weak` | All operations allowed, including from remote connections. |
**Notes:**
- `strong` is forced on outdated ComfyUI versions.
- `normal` is the default and recommended for most users.
- `normal-` is for developers who need to install unregistered nodes locally.
- `weak` should only be used in isolated development environments.
### Changing Security Level
Edit `user/__manager/config.ini`:
```ini
[default]
security_level = normal
```
---
## Error Messages
### "comfyui_outdated" (HTTP 403)
This error appears when:
- Your ComfyUI doesn't have the System User Protection API
- All installations are blocked until you update ComfyUI
**Solution**: Update ComfyUI to the latest version.
### "security_level" (HTTP 403)
This error appears when:
- Your security level blocks the requested operation
- For example, `strong` level blocks all installations
**Solution**: Lower your security level in config.ini if appropriate for your use case.
---
## Security Warning: Suspicious Path
If you see this error on an **older** ComfyUI:
```
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
[ComfyUI-Manager] ERROR: Suspicious path detected!
- '__manager' exists with low security level: 'weak'
- Please verify manually:
/path/to/ComfyUI/user/__manager/config.ini
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
```
On older ComfyUI versions, the `__manager` directory is not normally created. If this directory exists, it may have been created externally. For safety, manually verify the contents of this directory before updating ComfyUI.
---
## Troubleshooting
### All my installations are blocked
**Check 1**: Is your ComfyUI updated?
- Old ComfyUI forces `security_level = strong`
- Update ComfyUI to resolve
**Check 2**: What's your security level?
- Check `user/__manager/config.ini`
- `security_level = strong` blocks all installations
### My snapshots are missing
Snapshots are not automatically migrated. You need to manually copy the `snapshots` folder from inside `.legacy-manager-backup` to the `user/__manager/` directory.
### I keep seeing the backup notification
Delete the `.legacy-manager-backup` folder inside `user/__manager/` after confirming you don't need any data from it.
### Snapshot restore is blocked
On old ComfyUI (without System User API), snapshot restore is blocked because security is forced to `strong`. Update ComfyUI to enable snapshot restore.
---
## File Structure Reference
```
user/
└── __manager/
├── config.ini # Manager configuration
├── channels.list # Custom node channels
├── snapshots/ # Environment snapshots
└── .legacy-manager-backup/ # Backup of old Manager data (temporary)
```
---
## Requirements
- **ComfyUI**: v0.3.76 or later (with System User Protection API)
- **ComfyUI-Manager**: V3.38 or later

View File

@ -2831,8 +2831,8 @@
"GoogleImagenEditNode",
"GoogleImagenNode",
"NanoBananaNode",
"Veo3VideoGenerator",
"VeoGeminiVideoGenerator"
"VeoGeminiVideoGenerator",
"VeoVertexVideoGenerator"
],
{
"title_aux": "ComfyUI-ExternalAPI-Helpers"
@ -6287,6 +6287,7 @@
"Multi-LoRA Loader Qwen",
"Multi-LoRA Loader Wan-i2v",
"Multi-LoRA Loader Wan-t2v",
"Multi-LoRA Loader Z-Image",
"Multi-LoRA Loader [PLATFORM_NAME]",
"Multi-LoRA Loader v02",
"MyCustomNode",
@ -6306,6 +6307,7 @@
],
"https://github.com/EricRollei/Comfy_HunyuanImage3": [
[
"HunyuanImage3ClearDownstream",
"HunyuanImage3ForceUnload",
"HunyuanImage3FullGPULoader",
"HunyuanImage3FullLoader",
@ -13828,10 +13830,12 @@
"GeomPackFixNormals",
"GeomPackFixSelfIntersectionsByPerturbation",
"GeomPackFixSelfIntersectionsByRemoval",
"GeomPackGetMeshFilename",
"GeomPackLoadMesh",
"GeomPackLoadMeshBatch",
"GeomPackLoadMeshBlend",
"GeomPackLoadMeshFBX",
"GeomPackMergeVertices",
"GeomPackMeshFromSkeleton",
"GeomPackMeshInfo",
"GeomPackMeshQuality",
@ -13848,6 +13852,7 @@
"GeomPackRemesh",
"GeomPackRemeshSelfIntersections",
"GeomPackRemeshWithTexture",
"GeomPackRemoveDegenerateFaces",
"GeomPackSaveMesh",
"GeomPackSaveMeshBatch",
"GeomPackTextureToGeometry",
@ -14400,6 +14405,8 @@
],
"https://github.com/Rizzlord/ComfyUI-RizzNodes": [
[
"BatchImagesToGrid",
"LoadMultiviewImages",
"RizzAlphaMargin",
"RizzBatchImageLoader",
"RizzBlur",
@ -14414,7 +14421,10 @@
"RizzModelBatchLoader",
"RizzPasteAndUnscale",
"RizzUpscaleImageBatch",
"SimplifyMesh"
"SaveMultiviewImages",
"SimplifyMesh",
"SplitImageBatch",
"VideoSecondsToLength"
],
{
"title_aux": "ComfyUI-RizzNodes"
@ -18907,6 +18917,7 @@
],
"https://github.com/WingeD123/ComfyUI_QwenVL_PromptCaption": [
[
"Ovis25Run",
"Qwen25Caption",
"Qwen25CaptionBatch",
"Qwen3Caption",
@ -23320,6 +23331,7 @@
],
"https://github.com/bradsec/ComfyUI_StringEssentials": [
[
"StringConditionalAppend",
"StringMultiReplace",
"StringPreview",
"StringStrip",
@ -26204,6 +26216,11 @@
"KlingImageGenerationNode",
"KlingLipSyncAudioToVideoNode",
"KlingLipSyncTextToVideoNode",
"KlingOmniProEditVideoNode",
"KlingOmniProFirstLastFrameNode",
"KlingOmniProImageToVideoNode",
"KlingOmniProTextToVideoNode",
"KlingOmniProVideoToVideoNode",
"KlingSingleImageVideoEffectNode",
"KlingStartEndFrameNode",
"KlingTextToVideoNode",
@ -29102,6 +29119,7 @@
"HunyuanVideoPromptExpander",
"HunyuanVideoTextEncoder",
"HunyuanVideoVisionLoader",
"LLMOutputParser",
"PromptKeyFilter",
"QwenDebugController",
"QwenEliGenEntityControl",
@ -29126,9 +29144,11 @@
"QwenVLTextEncoder",
"QwenVLTextEncoderAdvanced",
"TemplateInfluenceAnalyzer",
"ZImageEmptyLatent",
"ZImageTextEncoder",
"ZImageTextEncoderSimple",
"ZImageTurnBuilder"
"ZImageTurnBuilder",
"ZImageWanVAEDecode"
],
{
"title_aux": "ComfyUI-QwenImageWanBridge"
@ -30634,6 +30654,10 @@
"Kling21Pro_fal",
"Kling25TurboPro_fal",
"KlingMaster_fal",
"KlingOmniImageToVideo_fal",
"KlingOmniReferenceToVideo_fal",
"KlingOmniVideoToVideoEdit_fal",
"KlingOmniVideoToVideoReference_fal",
"KlingPro10_fal",
"KlingPro16_fal",
"Kling_fal",
@ -31806,10 +31830,9 @@
],
"https://github.com/hobinrude/ComfyUI_DWposeDeluxe": [
[
"DWposeKeypointConverter",
"DWposeWeightOptions",
"FrameNumberNode",
"KeypointConverter",
"LoadPoseKeypoints",
"WeightOptions"
],
{
@ -36486,7 +36509,9 @@
[
"QwenImageEditScale",
"QwenImageEditSimpleScale",
"TextEncodeQwenImageEditAdv"
"TextEncodeQwenImageEditAdv",
"TextEncodeQwenImageEditInfAdv",
"TextEncodeQwenImageEditPlusAdv"
],
{
"title_aux": "comfyui_qwen_image_edit_adv"
@ -38480,6 +38505,7 @@
"EasyResize",
"EasyWan22Prompt",
"Easy_Version",
"KoolookLoadCameraPosesAbsolute",
"easy_ImageBatch"
],
{
@ -42821,6 +42847,12 @@
"WaveSpeedAI Flux Kontext Max",
"WaveSpeedAI Flux Kontext Pro",
"WaveSpeedAI Google Nano Banana Edit",
"WaveSpeedAI Google Nano Banana Pro Edit",
"WaveSpeedAI Google Nano Banana Pro Edit Multi",
"WaveSpeedAI Google Nano Banana Pro Edit Ultra",
"WaveSpeedAI Google Nano Banana Pro Text to Image",
"WaveSpeedAI Google Nano Banana Pro Text to Image Multi",
"WaveSpeedAI Google Nano Banana Pro Text to Image Ultra",
"WaveSpeedAI Google Nano Banana Text to Image",
"WaveSpeedAI Google VEO 3.1 Fast Image-to-Video",
"WaveSpeedAI Google VEO 3.1 Fast Text-to-Video",
@ -45260,8 +45292,11 @@
],
"https://github.com/smthemex/ComfyUI_DiffuEraser": [
[
"DiffuEraserLoader",
"DiffuEraserSampler"
"DiffuEraser_Loader",
"DiffuEraser_PreData",
"DiffuEraser_Sampler",
"Propainter_Loader",
"Propainter_Sampler"
],
{
"title_aux": "ComfyUI_DiffuEraser"

File diff suppressed because it is too large Load Diff

View File

@ -40,10 +40,11 @@ import cnr_utils
import manager_util
import git_utils
import manager_downloader
import manager_migration
from node_package import InstalledNodePackage
version_code = [3, 37, 2]
version_code = [3, 38]
version_str = f"V{version_code[0]}.{version_code[1]}" + (f'.{version_code[2]}' if len(version_code) > 2 else '')
@ -214,9 +215,10 @@ def update_user_directory(user_dir):
global manager_pip_blacklist_path
global manager_components_path
manager_files_path = os.path.abspath(os.path.join(user_dir, 'default', 'ComfyUI-Manager'))
manager_files_path = manager_migration.get_manager_path(user_dir)
if not os.path.exists(manager_files_path):
os.makedirs(manager_files_path)
manager_migration.run_migration_checks(user_dir, manager_files_path)
manager_snapshot_path = os.path.join(manager_files_path, "snapshots")
if not os.path.exists(manager_snapshot_path):
@ -1719,7 +1721,7 @@ def read_config():
manager_util.use_uv = default_conf['use_uv'].lower() == 'true' if 'use_uv' in default_conf else False
manager_util.bypass_ssl = get_bool('bypass_ssl', False)
return {
result = {
'http_channel_enabled': get_bool('http_channel_enabled', False),
'preview_method': default_conf.get('preview_method', manager_funcs.get_current_preview_method()).lower(),
'git_exe': default_conf.get('git_exe', ''),
@ -1739,6 +1741,8 @@ def read_config():
'security_level': default_conf.get('security_level', 'normal').lower(),
'db_mode': default_conf.get('db_mode', 'cache').lower(),
}
manager_migration.force_security_level_if_needed(result)
return result
except Exception:
import importlib.util
@ -1746,7 +1750,7 @@ def read_config():
manager_util.use_uv = importlib.util.find_spec("uv") is not None and platform.system() != "Windows"
manager_util.bypass_ssl = False
return {
result = {
'http_channel_enabled': False,
'preview_method': manager_funcs.get_current_preview_method(),
'git_exe': '',
@ -1766,6 +1770,8 @@ def read_config():
'security_level': 'normal', # strong | normal | normal- | weak
'db_mode': 'cache', # local | cache | remote
}
manager_migration.force_security_level_if_needed(result)
return result
def get_config():
@ -3361,7 +3367,7 @@ def get_comfyui_versions(repo=None):
try:
remote = get_remote_name(repo)
repo.remotes[remote].fetch()
except Exception:
except:
logging.error("[ComfyUI-Manager] Failed to fetch ComfyUI")
def parse_semver(tag_name):

356
glob/manager_migration.py Normal file
View File

@ -0,0 +1,356 @@
"""
ComfyUI-Manager migration module.
Handles migration from legacy paths to new __manager path structure.
"""
import os
import sys
import subprocess
import configparser
# Startup notices for notice board
startup_notices = [] # List of (message, level) tuples
def add_startup_notice(message, level='warning'):
"""Add a notice to be displayed on Manager notice board.
Args:
message: HTML-formatted message string
level: 'warning', 'error', 'info'
"""
global startup_notices
startup_notices.append((message, level))
# Cache for API check (computed once per session)
_cached_has_system_user_api = None
def has_system_user_api():
"""Check if ComfyUI has the System User Protection API (PR #10966).
Result is cached for performance.
"""
global _cached_has_system_user_api
if _cached_has_system_user_api is None:
try:
import folder_paths
_cached_has_system_user_api = hasattr(folder_paths, 'get_system_user_directory')
except Exception:
_cached_has_system_user_api = False
return _cached_has_system_user_api
def get_manager_path(user_dir):
"""Get the appropriate manager files path based on ComfyUI version.
Returns:
str: manager_files_path
"""
if has_system_user_api():
return os.path.abspath(os.path.join(user_dir, '__manager'))
else:
return os.path.abspath(os.path.join(user_dir, 'default', 'ComfyUI-Manager'))
def run_migration_checks(user_dir, manager_files_path):
"""Run all migration and security checks.
Call this after get_manager_path() to handle:
- Legacy config migration (new ComfyUI)
- Legacy backup notification (every startup)
- Suspicious directory detection (old ComfyUI)
- Outdated ComfyUI warning (old ComfyUI)
"""
if has_system_user_api():
migrated = migrate_legacy_config(user_dir, manager_files_path)
# Only check for legacy backup if migration didn't just happen
# (migration already shows backup location in its message)
if not migrated:
check_legacy_backup(manager_files_path)
else:
check_suspicious_manager(user_dir)
warn_outdated_comfyui()
def check_legacy_backup(manager_files_path):
"""Check for legacy backup and notify user to verify and remove it.
This runs on every startup to remind users about pending legacy backup.
"""
backup_dir = os.path.join(manager_files_path, '.legacy-manager-backup')
if not os.path.exists(backup_dir):
return
# Terminal output
print("\n" + "-"*70)
print("[ComfyUI-Manager] NOTICE: Legacy backup exists")
print(" - Your old Manager data was backed up to:")
print(f" {backup_dir}")
print(" - Please verify and remove it when no longer needed.")
print("-"*70 + "\n")
# Notice board output
add_startup_notice(
"Legacy ComfyUI-Manager data backup exists. Please verify and remove when no longer needed.",
level='info'
)
def check_suspicious_manager(user_dir):
"""Check for suspicious __manager directory on old ComfyUI.
On old ComfyUI without System User API, if __manager exists with low security,
warn the user to verify manually.
Returns:
bool: True if suspicious setup detected
"""
if has_system_user_api():
return False # Not suspicious on new ComfyUI
suspicious_path = os.path.abspath(os.path.join(user_dir, '__manager'))
if not os.path.exists(suspicious_path):
return False
config_path = os.path.join(suspicious_path, 'config.ini')
if not os.path.exists(config_path):
return False
config = configparser.ConfigParser()
config.read(config_path)
sec_level = config.get('default', 'security_level', fallback='normal').lower()
if sec_level in ['weak', 'normal-']:
# Terminal output
print("\n" + "!"*70)
print("[ComfyUI-Manager] ERROR: Suspicious path detected!")
print(f" - '__manager' exists with low security level: '{sec_level}'")
print(" - Please verify manually:")
print(f" {config_path}")
print("!"*70 + "\n")
# Notice board output
add_startup_notice(
"[Security Alert] Suspicious path detected. See terminal log for details.",
level='error'
)
return True
return False
def warn_outdated_comfyui():
"""Warn user about outdated ComfyUI without System User API."""
if has_system_user_api():
return
# Terminal output
print("\n" + "!"*70)
print("[ComfyUI-Manager] ERROR: ComfyUI version is outdated!")
print(" - Most operations are blocked for security.")
print(" - ComfyUI update is still allowed.")
print(" - Please update ComfyUI to use Manager normally.")
print("!"*70 + "\n")
# Notice board output
add_startup_notice(
"[Security Alert] ComfyUI outdated. Installations blocked (update allowed).<BR>"
"Update ComfyUI for normal operation.",
level='error'
)
def migrate_legacy_config(user_dir, manager_files_path):
"""Migrate ONLY config.ini to new __manager path if needed.
IMPORTANT: Only config.ini is migrated. Other files (snapshots, cache, etc.)
are NOT migrated - users must recreate them.
Scenarios:
1. Legacy exists, New doesn't exist → Migrate config.ini
2. Legacy exists, New exists First update after upgrade
- Run ComfyUI dependency installation
- Rename legacy to .backup
3. Legacy doesn't exist → No migration needed
Returns:
bool: True if migration was performed
"""
if not has_system_user_api():
return False
legacy_dir = os.path.join(user_dir, 'default', 'ComfyUI-Manager')
legacy_config = os.path.join(legacy_dir, 'config.ini')
new_config = os.path.join(manager_files_path, 'config.ini')
if not os.path.exists(legacy_dir):
return False # No legacy directory, nothing to migrate
# IMPORTANT: Check for config.ini existence, not just directory
# (because makedirs() creates __manager before this function is called)
# Case: Both configs exist (first update after ComfyUI upgrade)
# This means user ran new ComfyUI at least once, creating __manager/config.ini
if os.path.exists(legacy_config) and os.path.exists(new_config):
_handle_first_update_migration(user_dir, legacy_dir, manager_files_path)
return True
# Case: Legacy config exists but new config doesn't (normal migration)
# This is the first run after ComfyUI upgrade
if os.path.exists(legacy_config) and not os.path.exists(new_config):
pass # Continue with normal migration below
else:
return False
# Terminal output
print("\n" + "-"*70)
print("[ComfyUI-Manager] NOTICE: Legacy config.ini detected")
print(f" - Old: {legacy_config}")
print(f" - New: {new_config}")
print(" - Migrating config.ini only (other files are NOT migrated).")
print(" - Security level below 'normal' will be raised.")
print("-"*70 + "\n")
_migrate_config_with_security_check(legacy_config, new_config)
# Move legacy directory to backup
_move_legacy_to_backup(legacy_dir, manager_files_path)
return True
def _handle_first_update_migration(user_dir, legacy_dir, manager_files_path):
"""Handle first ComfyUI update when both legacy and new directories exist.
This scenario happens when:
- User was on old ComfyUI (using default/ComfyUI-Manager)
- ComfyUI was updated (now has System User API)
- Manager already created __manager on first new run
- But legacy directory still exists
Actions:
1. Run ComfyUI dependency installation
2. Move legacy to __manager/.legacy-manager-backup
"""
# Terminal output
print("\n" + "-"*70)
print("[ComfyUI-Manager] NOTICE: First update after ComfyUI upgrade detected")
print(" - Both legacy and new directories exist.")
print(" - Running ComfyUI dependency installation...")
print("-"*70 + "\n")
# Run ComfyUI dependency installation
# Path: glob/manager_migration.py → glob → comfyui-manager → custom_nodes → ComfyUI
try:
comfyui_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
requirements_path = os.path.join(comfyui_path, 'requirements.txt')
if os.path.exists(requirements_path):
subprocess.run([sys.executable, '-m', 'pip', 'install', '-r', requirements_path],
capture_output=True, check=False)
print("[ComfyUI-Manager] ComfyUI dependencies installation completed.")
except Exception as e:
print(f"[ComfyUI-Manager] WARNING: Failed to install ComfyUI dependencies: {e}")
# Move legacy to backup inside __manager
_move_legacy_to_backup(legacy_dir, manager_files_path)
def _move_legacy_to_backup(legacy_dir, manager_files_path):
"""Move legacy directory to backup inside __manager.
Returns:
str: Path to backup directory if successful, None if failed
"""
import shutil
backup_dir = os.path.join(manager_files_path, '.legacy-manager-backup')
try:
if os.path.exists(backup_dir):
shutil.rmtree(backup_dir) # Remove old backup if exists
shutil.move(legacy_dir, backup_dir)
# Terminal output (full paths shown here only)
print("\n" + "-"*70)
print("[ComfyUI-Manager] NOTICE: Legacy settings migrated")
print(f" - Old location: {legacy_dir}")
print(f" - Backed up to: {backup_dir}")
print(" - Please verify and remove the backup when no longer needed.")
print("-"*70 + "\n")
# Notice board output (no full paths for security)
add_startup_notice(
"Legacy ComfyUI-Manager data migrated. See terminal for details.",
level='info'
)
return backup_dir
except Exception as e:
print(f"[ComfyUI-Manager] WARNING: Failed to backup legacy directory: {e}")
add_startup_notice(
f"[MIGRATION] Failed to backup legacy directory: {e}",
level='warning'
)
return None
def _migrate_config_with_security_check(legacy_path, new_path):
"""Migrate legacy config, raising security level only if below default."""
config = configparser.ConfigParser()
try:
config.read(legacy_path)
except Exception as e:
print(f"[ComfyUI-Manager] WARNING: Failed to parse config.ini: {e}")
print(" - Creating fresh config with default settings.")
add_startup_notice(
"[MIGRATION] Failed to parse legacy config. Using defaults.",
level='warning'
)
return # Skip migration, let Manager create fresh config
# Security level hierarchy: strong > normal > normal- > weak
# Default is 'normal', only raise if below default
if 'default' in config:
current_level = config['default'].get('security_level', 'normal').lower()
below_default_levels = ['weak', 'normal-']
if current_level in below_default_levels:
config['default']['security_level'] = 'normal'
# Terminal output
print("\n" + "="*70)
print("[ComfyUI-Manager] WARNING: Security level adjusted")
print(f" - Previous: '{current_level}' → New: 'normal'")
print(" - Raised to prevent unauthorized remote access.")
print("="*70 + "\n")
# Notice board output
add_startup_notice(
f"[MIGRATION] Security level raised: '{current_level}''normal'.<BR>"
"To prevent unauthorized remote access.",
level='warning'
)
else:
print(f" - Security level: '{current_level}' (no change needed)")
# Ensure directory exists
os.makedirs(os.path.dirname(new_path), exist_ok=True)
with open(new_path, 'w') as f:
config.write(f)
def force_security_level_if_needed(config_dict):
"""Force security level to 'strong' if on old ComfyUI.
Args:
config_dict: Configuration dictionary to modify in-place
Returns:
bool: True if security level was forced
"""
if not has_system_user_api():
config_dict['security_level'] = 'strong'
return True
return False

View File

@ -22,6 +22,7 @@ import asyncio
import queue
import manager_downloader
import manager_migration
logging.info(f"### Loading: ComfyUI-Manager ({core.version_str})")
@ -276,6 +277,13 @@ import zipfile
import urllib.request
def security_403_response():
"""Return appropriate 403 response based on ComfyUI version."""
if not manager_migration.has_system_user_api():
return web.json_response({"error": "comfyui_outdated"}, status=403)
return web.json_response({"error": "security_level"}, status=403)
def get_model_dir(data, show_log=False):
if 'download_model_base' in folder_paths.folder_names_and_paths:
models_base = folder_paths.folder_names_and_paths['download_model_base'][0][0]
@ -732,7 +740,7 @@ async def fetch_updates(request):
async def update_all(request):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
return web.Response(status=403)
return security_403_response()
with task_worker_lock:
is_processing = task_worker_thread is not None and task_worker_thread.is_alive()
@ -965,7 +973,7 @@ async def get_snapshot_list(request):
async def remove_snapshot(request):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
return web.Response(status=403)
return security_403_response()
try:
target = request.rel_url.query["target"]
@ -983,7 +991,7 @@ async def remove_snapshot(request):
async def restore_snapshot(request):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
return web.Response(status=403)
return security_403_response()
try:
target = request.rel_url.query["target"]
@ -1302,7 +1310,7 @@ async def fix_custom_node(request):
async def install_custom_node_git_url(request):
if not is_allowed_security_level('high'):
logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
return web.Response(status=403)
return security_403_response()
url = await request.text()
res = await core.gitclone_install(url)
@ -1322,7 +1330,7 @@ async def install_custom_node_git_url(request):
async def install_custom_node_pip(request):
if not is_allowed_security_level('high'):
logging.error(SECURITY_MESSAGE_NORMAL_MINUS)
return web.Response(status=403)
return security_403_response()
packages = await request.text()
core.pip_install(packages.split(' '))
@ -1594,6 +1602,16 @@ async def get_notice(request):
except:
pass
# Prepend startup notices from manager_migration
for message, level in reversed(manager_migration.startup_notices):
if level == 'error':
style = 'color:red; background-color:white; font-weight:bold'
elif level == 'warning':
style = 'color:orange; background-color:white; font-weight:bold'
else:
style = 'color:blue; background-color:white'
markdown_content = f'<P style="{style}">{message}</P>' + markdown_content
return web.Response(text=markdown_content, status=200)
else:
return web.Response(text="Unable to retrieve Notice", status=200)
@ -1601,11 +1619,35 @@ async def get_notice(request):
return web.Response(text="Unable to retrieve Notice", status=200)
@routes.get("/manager/startup_alerts")
async def get_startup_alerts(request):
"""Return startup alerts for customAlert display on page load.
Returns JSON array of alerts that should be shown to user immediately.
All startup notices (error, warning, info) are returned.
"""
alerts = []
# Return all startup notices for alert display
for message, level in manager_migration.startup_notices:
# Convert HTML BR to newlines for customAlert
text = message.replace('<BR>', '\n').replace('<br>', '\n')
# Add [ComfyUI-Manager] prefix for customAlert (notice board shows in Manager UI anyway)
text = text.replace('[Security Alert]', '[ComfyUI-Manager] Security Alert:')
text = text.replace('[MIGRATION]', '[ComfyUI-Manager] Migration:')
alerts.append({
'message': text,
'level': level
})
return web.json_response(alerts)
@routes.get("/manager/reboot")
def restart(self):
if not is_allowed_security_level('middle'):
logging.error(SECURITY_MESSAGE_MIDDLE_OR_BELOW)
return web.Response(status=403)
return security_403_response()
try:
sys.stdout.close_log()

View File

@ -1,6 +1,6 @@
import { api } from "../../scripts/api.js";
import { app } from "../../scripts/app.js";
import { sleep, customConfirm, customAlert } from "./common.js";
import { sleep, customConfirm, customAlert, handle403Response, show_message } from "./common.js";
async function tryInstallCustomNode(event) {
let msg = '-= [ComfyUI Manager] extension installation request =-\n\n';
@ -42,7 +42,7 @@ async function tryInstallCustomNode(event) {
});
if(response.status == 403) {
show_message('This action is not allowed with this security level configuration.');
await handle403Response(response);
return false;
}
else if(response.status == 400) {
@ -54,7 +54,7 @@ async function tryInstallCustomNode(event) {
let response = await api.fetchApi("/manager/reboot");
if(response.status == 403) {
show_message('This action is not allowed with this security level configuration.');
await handle403Response(response);
return false;
}

View File

@ -14,7 +14,7 @@ import { OpenArtShareDialog } from "./comfyui-share-openart.js";
import {
free_models, install_pip, install_via_git_url, manager_instance,
rebootAPI, setManagerInstance, show_message, customAlert, customPrompt,
infoToast, showTerminal, setNeedRestart
infoToast, showTerminal, setNeedRestart, handle403Response
} from "./common.js";
import { ComponentBuilderDialog, getPureName, load_components, set_component_policy } from "./components-manager.js";
import { CustomNodesManager } from "./custom-nodes-manager.js";
@ -753,9 +753,9 @@ async function onQueueStatus(event) {
const rebootButton = document.getElementById('cm-reboot-button5');
rebootButton?.addEventListener("click",
function() {
if(rebootAPI()) {
manager_dialog.close();
async function() {
if(await rebootAPI()) {
manager_instance.close();
}
});
}
@ -780,8 +780,13 @@ async function updateAll(update_comfyui) {
const response = await api.fetchApi(`/manager/queue/update_all?mode=${mode}`);
if (response.status == 401) {
if (response.status == 403) {
await handle403Response(response);
reset_action_buttons();
}
else if (response.status == 401) {
customAlert('Another task is already in progress. Please stop the ongoing task first.');
reset_action_buttons();
}
else if(response.status == 200) {
is_updating = true;
@ -1453,6 +1458,31 @@ app.registerExtension({
load_components();
// Fetch and show startup alerts (critical errors like outdated ComfyUI)
// Poll until extensionManager.toast is ready (set in Vue onMounted)
const showStartupAlerts = async () => {
let toastWaitCount = 0;
const waitForToast = () => {
if (window['app']?.extensionManager?.toast) {
fetch('/manager/startup_alerts')
.then(response => response.ok ? response.json() : [])
.then(alerts => {
for (const alert of alerts) {
customAlert(alert.message);
}
})
.catch(e => console.warn('[ComfyUI-Manager] Failed to fetch startup alerts:', e));
} else if (toastWaitCount < 300) { // Max 30 seconds (300 * 100ms)
toastWaitCount++;
setTimeout(waitForToast, 100);
} else {
console.warn('[ComfyUI-Manager] Timeout waiting for toast. Startup alerts skipped.');
}
};
waitForToast();
};
showStartupAlerts();
const menu = document.querySelector(".comfy-menu");
const separator = document.createElement("hr");

View File

@ -100,6 +100,19 @@ export function show_message(msg) {
app.ui.dialog.element.style.zIndex = 1100;
}
export async function handle403Response(res, defaultMessage) {
try {
const data = await res.json();
if(data.error === 'comfyui_outdated') {
show_message('ComfyUI version is outdated.<BR>Please update ComfyUI to use Manager normally.');
} else {
show_message(defaultMessage || 'This action is not allowed with this security level configuration.');
}
} catch {
show_message(defaultMessage || 'This action is not allowed with this security level configuration.');
}
}
export async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
@ -163,20 +176,23 @@ export async function customPrompt(title, message) {
}
export function rebootAPI() {
export async function rebootAPI() {
if ('electronAPI' in window) {
window.electronAPI.restartApp();
return true;
}
customConfirm("Are you sure you'd like to reboot the server?").then((isConfirmed) => {
if (isConfirmed) {
try {
api.fetchApi("/manager/reboot");
const isConfirmed = await customConfirm("Are you sure you'd like to reboot the server?");
if (isConfirmed) {
try {
const response = await api.fetchApi("/manager/reboot");
if (response.status == 403) {
await handle403Response(response);
return false;
}
catch(exception) {}
}
});
catch(exception) {}
}
return false;
}
@ -216,7 +232,7 @@ export async function install_pip(packages) {
});
if(res.status == 403) {
show_message('This action is not allowed with this security level configuration.');
await handle403Response(res);
return;
}
@ -251,7 +267,7 @@ export async function install_via_git_url(url, manager_dialog) {
});
if(res.status == 403) {
show_message('This action is not allowed with this security level configuration.');
await handle403Response(res);
return;
}
@ -262,9 +278,9 @@ export async function install_via_git_url(url, manager_dialog) {
const self = this;
rebootButton.addEventListener("click",
function() {
if(rebootAPI()) {
manager_dialog.close();
async function() {
if(await rebootAPI()) {
manager_instance.close();
}
});
}

View File

@ -7,7 +7,7 @@ import {
fetchData, md5, icons, show_message, customConfirm, customAlert, customPrompt,
sanitizeHTML, infoToast, showTerminal, setNeedRestart,
storeColumnWidth, restoreColumnWidth, getTimeAgo, copyText, loadCss,
showPopover, hidePopover
showPopover, hidePopover, handle403Response
} from "./common.js";
// https://cenfun.github.io/turbogrid/api.html
@ -1528,7 +1528,16 @@ export class CustomNodesManager {
errorMsg = `'${item.title}': `;
if(res.status == 403) {
errorMsg += `This action is not allowed with this security level configuration.\n`;
try {
const data = await res.json();
if(data.error === 'comfyui_outdated') {
errorMsg += `ComfyUI version is outdated. Please update ComfyUI to use Manager normally.\n`;
} else {
errorMsg += `This action is not allowed with this security level configuration.\n`;
}
} catch {
errorMsg += `This action is not allowed with this security level configuration.\n`;
}
} else if(res.status == 404) {
errorMsg += `With the current security level configuration, only custom nodes from the <B>"default channel"</B> can be installed.\n`;
} else {

View File

@ -1,9 +1,9 @@
import { app } from "../../scripts/app.js";
import { $el } from "../../scripts/ui.js";
import {
manager_instance, rebootAPI,
import {
manager_instance, rebootAPI,
fetchData, md5, icons, show_message, customAlert, infoToast, showTerminal,
storeColumnWidth, restoreColumnWidth, loadCss
storeColumnWidth, restoreColumnWidth, loadCss, handle403Response
} from "./common.js";
import { api } from "../../scripts/api.js";
@ -477,7 +477,16 @@ export class ModelManager {
errorMsg = `'${item.name}': `;
if(res.status == 403) {
errorMsg += `This action is not allowed with this security level configuration.\n`;
try {
const data = await res.json();
if(data.error === 'comfyui_outdated') {
errorMsg += `ComfyUI version is outdated. Please update ComfyUI to use Manager normally.\n`;
} else {
errorMsg += `This action is not allowed with this security level configuration.\n`;
}
} catch {
errorMsg += `This action is not allowed with this security level configuration.\n`;
}
} else {
errorMsg += await res.text() + '\n';
}

View File

@ -1,7 +1,7 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js"
import { ComfyDialog, $el } from "../../scripts/ui.js";
import { manager_instance, rebootAPI, show_message } from "./common.js";
import { manager_instance, rebootAPI, show_message, handle403Response } from "./common.js";
async function restore_snapshot(target) {
@ -10,7 +10,7 @@ async function restore_snapshot(target) {
const response = await api.fetchApi(`/snapshot/restore?target=${target}`, { cache: "no-store" });
if(response.status == 403) {
show_message('This action is not allowed with this security level configuration.');
await handle403Response(response);
return false;
}
@ -38,7 +38,7 @@ async function remove_snapshot(target) {
const response = await api.fetchApi(`/snapshot/remove?target=${target}`, { cache: "no-store" });
if(response.status == 403) {
show_message('This action is not allowed with this security level configuration.');
await handle403Response(response);
return false;
}
@ -145,8 +145,8 @@ export class SnapshotManager extends ComfyDialog {
if(btn_id) {
const rebootButton = document.getElementById(btn_id);
const self = this;
rebootButton.onclick = function() {
if(rebootAPI()) {
rebootButton.onclick = async function() {
if(await rebootAPI()) {
self.close();
self.manager_dialog.close();
}

View File

@ -1,5 +1,78 @@
{
"custom_nodes": [
{
"author": "HAL-XP",
"title": "HALXP-Comfy",
"reference": "https://github.com/hal-xp/halxp-comfy",
"files": [
"https://github.com/hal-xp/halxp-comfy"
],
"install_type": "git-clone",
"description": "A UI suite for ComfyUI including Focus mode and layout enhancements."
},
{
"author": "BuddyBytes",
"title": "Smart Resolution Toolkit",
"reference": "https://github.com/buddy-bytes/ComfyUI-SmartResolutionToolkit",
"files": [
"https://github.com/buddy-bytes/ComfyUI-SmartResolutionToolkit"
],
"install_type": "git-clone",
"description": "Resolution picker and latent generator for ComfyUI. Select presets like HD, FullHD, 2K, 4K, 8K with aspect ratios (1:1, 9:16, 4:5, 21:9 etc.) via dropdowns. Automatically snaps width/height to latent-safe multiples of 64. Ideal for EmptyLatentImage, AnimateDiff, ControlNet, video formats, and KSampler workflows. Outputs clean INT values or ready-to-use LATENT tensor."
},
{
"author": "Bharanidharan",
"title": "iSeeBetter Node for ComfyUI",
"reference": "https://github.com/llikethat/ComfyUI-iseebetter",
"files": [
"https://github.com/llikethat/ComfyUI-iseebetter"
],
"install_type": "git-clone",
"description": "Custom Node to implement iSeeBetter upscaling method."
},
{
"author": "Pondowner857",
"title": "ComfyUI Remote Workflow Executor",
"id": "comfy_Pond_Nodes_V2",
"reference": "https://github.com/Pondowner857/comfy_Pond_Nodes_V2",
"files": [
"https://github.com/Pondowner857/comfy_Pond_Nodes_V2"
],
"install_type": "git-clone",
"description": "Remote workflow executor node - Execute workflows on remote ComfyUI servers. Supports image/text/audio/video input and output."
},
{
"author": "luxdelux7",
"title": "Forbidden Vision",
"reference": "https://github.com/luxdelux7/ComfyUI-Forbidden-Vision",
"files": [
"https://github.com/luxdelux7/ComfyUI-Forbidden-Vision"
],
"install_type": "git-clone",
"description": "Custom face detection and segmentation for ComfyUI with automatic face fixing, intelligent color grading, and iterative refinement. Custom-trained models optimized for realistic, anime, and NSFW content.",
"nodename_pattern": "ForbiddenVision"
},
{
"author": "Kazama-Suichiku",
"title": "ComfyUI-Meshy",
"id": "comfyui-meshy",
"reference": "https://github.com/Kazama-Suichiku/ComfyUI-Meshy",
"files": [
"https://github.com/Kazama-Suichiku/ComfyUI-Meshy"
],
"install_type": "git-clone",
"description": "ComfyUI-Meshy is a 3D generation extension based on Meshy AI API. It provides Text-to-3D and Image-to-3D capabilities within ComfyUI, allowing you to generate 3D models directly from text prompts or images. Supports multiple AI models (Meshy-4, Meshy-5, Meshy-6) with customizable topology, polygon count, and PBR settings."
},
{
"author": "ah-kun",
"title": "ComfyUI-FailSafe-Translate-Node",
"reference": "https://github.com/ah-kun/ComfyUI-FailSafe-Translate-Node",
"files": [
"https://github.com/ah-kun/ComfyUI-FailSafe-Translate-Node"
],
"install_type": "git-clone",
"description": "Fail-safe Google Translate prompt node for ComfyUI (retry + caching)."
},
{
"author": "princepainter",
"title": "PainterFLF2V - First/Last Frame Video Enhancer",
@ -656,196 +729,6 @@
],
"install_type": "git-clone",
"description": "ComfyUI integration for Meta's SAM3 model enabling open-vocabulary image segmentation using natural language text prompts, with automatic model download, geometric refinement, and flexible confidence thresholds."
},
{
"author": "wwzhifeng",
"title": "comfyui-jsonprompt",
"reference": "https://github.com/wwzhifeng/comfyui-jsonprompt",
"files": [
"https://github.com/wwzhifeng/comfyui-jsonprompt"
],
"install_type": "git-clone",
"description": "Custom ComfyUI node that expands structured JSON text into standard prompts for use with models like Gemini, Flux, OpenAI, and Sora. (Description by CC)"
},
{
"author": "StarIICraft",
"title": "ComfyUI-Simple-Selector",
"reference": "https://github.com/StarIICraft/ComfyUI-Simple-Selector",
"files": [
"https://github.com/StarIICraft/ComfyUI-Simple-Selector"
],
"install_type": "git-clone",
"description": "Logic control node with 5 universal input ports that checks connections in reverse priority order and outputs the index of the first valid active input, with support for muted nodes and any data type."
},
{
"author": "fr0nky0ng",
"title": "ComfyUI-JSON-Prompt",
"reference": "https://github.com/fr0nky0ng/ComfyUI-JSON-Prompt",
"files": [
"https://github.com/fr0nky0ng/ComfyUI-JSON-Prompt"
],
"install_type": "git-clone",
"description": "Custom node for ComfyUI that generates JSON prompts from natural language descriptions to improve text-to-image generation quality. Supports local LLM integration via Ollama or Google Gemini API."
},
{
"author": "EricRollei",
"title": "Eric_Image_Processing_Nodes",
"reference": "https://github.com/EricRollei/Eric_Image_Processing_Nodes",
"files": [
"https://github.com/EricRollei/Eric_Image_Processing_Nodes"
],
"install_type": "git-clone",
"description": "A comprehensive collection of advanced image processing nodes for ComfyUI, featuring state-of-the-art denoising, enhancement, and restoration techniques with GPU acceleration and specialized film grain processing."
},
{
"author": "huyl3-cpu",
"title": "comfyui-huyl2-nodes",
"reference": "https://github.com/huyl3-cpu/comfyui-sortlist",
"files": [
"https://github.com/huyl3-cpu/comfyui-sortlist"
],
"install_type": "git-clone",
"description": "Custom utility nodes for ComfyUI by huyl2 (sort list v2, etc.)"
},
{
"author": "7BEII",
"title": "comfyui-PD_comfy-api-node",
"reference": "https://github.com/7BEII/comfyui-PD_comfy-api-node",
"files": [
"https://github.com/7BEII/comfyui-PD_comfy-api-node"
],
"install_type": "git-clone",
"description": "ComfyUI custom node suite integrating multiple AI image generation APIs (Gemini, Flux.1 Kontext Pro) with unified authentication via ComfyUI API Key and real-time cost tracking. (Description by CC)"
},
{
"author": "wallen0322",
"title": "ComfyUI-AE-Animation",
"reference": "https://github.com/wallen0322/ComfyUI-AE-Animation",
"files": [
"https://github.com/wallen0322/ComfyUI-AE-Animation"
],
"install_type": "git-clone",
"description": "After Effects-style animation nodes for ComfyUI with timeline-based keyframe control, layer management, and real-time preview rendering. (Description by CC)"
},
{
"author": "wallen0322",
"title": "ComfyUI-TTM-WAN22",
"reference": "https://github.com/wallen0322/ComfyUI-TTM-WAN22",
"files": [
"https://github.com/wallen0322/ComfyUI-TTM-WAN22"
],
"install_type": "git-clone",
"description": "TTM (Time-to-Move) node for ComfyUI enabling motion-controlled video generation with Wan2.2 models using dual-clock denoising for independent background and object animation control."
},
{
"author": "swan7-py",
"title": "ComfyUI-ImageAlphaCrop",
"reference": "https://github.com/swan7-py/ComfyUI-ImageAlphaCrop",
"files": [
"https://github.com/swan7-py/ComfyUI-ImageAlphaCrop"
],
"install_type": "git-clone",
"description": "ComfyUI plugin for automatically cropping transparent alpha channel borders from images - ideal for processing logos and icons. Supports batch processing with adjustable padding and alpha threshold. (Description by CC)"
},
{
"author": "was",
"title": "WAS LMStudio Easy-Query",
"reference": "https://github.com/WASasquatch/ComfyUI_LMStudio_EasyQuery",
"files": [
"https://github.com/WASasquatch/ComfyUI_LMStudio_EasyQuery"
],
"install_type": "git-clone",
"description": "LM Studio calls with image support and easy task directions."
},
{
"author": "PozzettiAndrea",
"title": "ComfyUI-AnyTop",
"reference": "https://github.com/PozzettiAndrea/ComfyUI-AnyTop",
"files": [
"https://github.com/PozzettiAndrea/ComfyUI-AnyTop"
],
"install_type": "git-clone",
"description": "Standalone ComfyUI custom nodes for AnyTop - Universal Motion Generation for Any Skeleton Topology."
},
{
"author": "IamCreateAI",
"title": "ComfyUI-Animon",
"reference": "https://github.com/IamCreateAI/ComfyUI-Animon",
"files": [
"https://github.com/IamCreateAI/ComfyUI-Animon"
],
"install_type": "git-clone",
"description": "ComfyUI nodes for [Animon Platform](https://platform.animon.ai/), a comprehensive API service offering a variety of image and video generation models."
},
{
"author": "neonr0",
"title": "ComfyUI-PixelConstrainedScaler",
"reference": "https://github.com/neonr-0/ComfyUI-PixelConstrainedScaler",
"files": [
"https://github.com/neonr-0/ComfyUI-PixelConstrainedScaler"
],
"install_type": "git-clone",
"description": "Smart upscaling with pixel-budget awareness while preserving native aspect ratios. Ideal for Image to Image (I2I) and Image to Video (I2V) workflows!"
},
{
"author": "slahiri",
"title": "ComfyUI-AI-Photography-Toolkit",
"reference": "https://github.com/slahiri/ComfyUI-AI-Photography-Toolkit",
"files": [
"https://github.com/slahiri/ComfyUI-AI-Photography-Toolkit"
],
"install_type": "git-clone",
"description": "A collection of AI-powered photography and image generation tools for ComfyUI, featuring the SID_AIPromptGenerator node that uses Anthropic's Claude API to analyze images and generate optimized prompts for various image generation models."
},
{
"author": "wzyfromhust",
"title": "ComfyUI_SAM2UltraV2",
"reference": "https://github.com/wzyfromhust/ComfyUI_SAM2UltraV2",
"files": [
"https://github.com/wzyfromhust/ComfyUI_SAM2UltraV2"
],
"install_type": "git-clone",
"description": "A fully modular and high-performance implementation of SAM2 (Segment Anything Model 2) for ComfyUI with dual-prompt support, negative point sampling, and upper body segmentation."
},
{
"author": "cedarconnor",
"title": "ComfyUI-DreamCube",
"reference": "https://github.com/cedarconnor/ComfyUI-DreamCube",
"files": [
"https://github.com/cedarconnor/ComfyUI-DreamCube"
],
"install_type": "git-clone",
"description": "360° panoramic depth estimation with multi-plane synchronization for ComfyUI, featuring equirectangular-cubemap transformations, cross-face consistency, and boundary blending for seamless depth maps."
},
{
"author": "dowa-git",
"title": "comfyui-dowa",
"reference": "https://github.com/dowa-git/comfyui-dowa",
"files": [
"https://github.com/dowa-git/comfyui-dowa"
],
"install_type": "git-clone",
"description": "Professional navigation bar widget for ComfyUI with JWT-based user authentication, workflow templates, and team collaboration features in a purple gradient design."
},
{
"author": "fuselayer",
"title": "comfyui-lite-tracker",
"reference": "https://github.com/fuselayer/comfyui-lite-tracker",
"files": [
"https://github.com/fuselayer/comfyui-lite-tracker"
],
"install_type": "git-clone",
"description": "ComfyUI custom nodes for LiteTracker, a fast and efficient point tracking model for videos with load model, track, and grid editor nodes."
},
{
"author": "yichengup",
"title": "ComfyUI-YCNodes_Toolkit",
"reference": "https://github.com/yichengup/ComfyUI-YCNodes_Toolkit",
"files": [
"https://github.com/yichengup/ComfyUI-YCNodes_Toolkit"
],
"install_type": "git-clone",
"description": "ComfyUI toolkit with custom nodes for BBox canvas visualization, image brush mask drawing, and coordinate annotation for debugging and external data bridging. (Description by CC)"
}
]
}

View File

@ -2831,8 +2831,8 @@
"GoogleImagenEditNode",
"GoogleImagenNode",
"NanoBananaNode",
"Veo3VideoGenerator",
"VeoGeminiVideoGenerator"
"VeoGeminiVideoGenerator",
"VeoVertexVideoGenerator"
],
{
"title_aux": "ComfyUI-ExternalAPI-Helpers"
@ -6287,6 +6287,7 @@
"Multi-LoRA Loader Qwen",
"Multi-LoRA Loader Wan-i2v",
"Multi-LoRA Loader Wan-t2v",
"Multi-LoRA Loader Z-Image",
"Multi-LoRA Loader [PLATFORM_NAME]",
"Multi-LoRA Loader v02",
"MyCustomNode",
@ -6306,6 +6307,7 @@
],
"https://github.com/EricRollei/Comfy_HunyuanImage3": [
[
"HunyuanImage3ClearDownstream",
"HunyuanImage3ForceUnload",
"HunyuanImage3FullGPULoader",
"HunyuanImage3FullLoader",
@ -13828,10 +13830,12 @@
"GeomPackFixNormals",
"GeomPackFixSelfIntersectionsByPerturbation",
"GeomPackFixSelfIntersectionsByRemoval",
"GeomPackGetMeshFilename",
"GeomPackLoadMesh",
"GeomPackLoadMeshBatch",
"GeomPackLoadMeshBlend",
"GeomPackLoadMeshFBX",
"GeomPackMergeVertices",
"GeomPackMeshFromSkeleton",
"GeomPackMeshInfo",
"GeomPackMeshQuality",
@ -13848,6 +13852,7 @@
"GeomPackRemesh",
"GeomPackRemeshSelfIntersections",
"GeomPackRemeshWithTexture",
"GeomPackRemoveDegenerateFaces",
"GeomPackSaveMesh",
"GeomPackSaveMeshBatch",
"GeomPackTextureToGeometry",
@ -14400,6 +14405,8 @@
],
"https://github.com/Rizzlord/ComfyUI-RizzNodes": [
[
"BatchImagesToGrid",
"LoadMultiviewImages",
"RizzAlphaMargin",
"RizzBatchImageLoader",
"RizzBlur",
@ -14414,7 +14421,10 @@
"RizzModelBatchLoader",
"RizzPasteAndUnscale",
"RizzUpscaleImageBatch",
"SimplifyMesh"
"SaveMultiviewImages",
"SimplifyMesh",
"SplitImageBatch",
"VideoSecondsToLength"
],
{
"title_aux": "ComfyUI-RizzNodes"
@ -18907,6 +18917,7 @@
],
"https://github.com/WingeD123/ComfyUI_QwenVL_PromptCaption": [
[
"Ovis25Run",
"Qwen25Caption",
"Qwen25CaptionBatch",
"Qwen3Caption",
@ -23320,6 +23331,7 @@
],
"https://github.com/bradsec/ComfyUI_StringEssentials": [
[
"StringConditionalAppend",
"StringMultiReplace",
"StringPreview",
"StringStrip",
@ -26204,6 +26216,11 @@
"KlingImageGenerationNode",
"KlingLipSyncAudioToVideoNode",
"KlingLipSyncTextToVideoNode",
"KlingOmniProEditVideoNode",
"KlingOmniProFirstLastFrameNode",
"KlingOmniProImageToVideoNode",
"KlingOmniProTextToVideoNode",
"KlingOmniProVideoToVideoNode",
"KlingSingleImageVideoEffectNode",
"KlingStartEndFrameNode",
"KlingTextToVideoNode",
@ -29102,6 +29119,7 @@
"HunyuanVideoPromptExpander",
"HunyuanVideoTextEncoder",
"HunyuanVideoVisionLoader",
"LLMOutputParser",
"PromptKeyFilter",
"QwenDebugController",
"QwenEliGenEntityControl",
@ -29126,9 +29144,11 @@
"QwenVLTextEncoder",
"QwenVLTextEncoderAdvanced",
"TemplateInfluenceAnalyzer",
"ZImageEmptyLatent",
"ZImageTextEncoder",
"ZImageTextEncoderSimple",
"ZImageTurnBuilder"
"ZImageTurnBuilder",
"ZImageWanVAEDecode"
],
{
"title_aux": "ComfyUI-QwenImageWanBridge"
@ -30634,6 +30654,10 @@
"Kling21Pro_fal",
"Kling25TurboPro_fal",
"KlingMaster_fal",
"KlingOmniImageToVideo_fal",
"KlingOmniReferenceToVideo_fal",
"KlingOmniVideoToVideoEdit_fal",
"KlingOmniVideoToVideoReference_fal",
"KlingPro10_fal",
"KlingPro16_fal",
"Kling_fal",
@ -31806,10 +31830,9 @@
],
"https://github.com/hobinrude/ComfyUI_DWposeDeluxe": [
[
"DWposeKeypointConverter",
"DWposeWeightOptions",
"FrameNumberNode",
"KeypointConverter",
"LoadPoseKeypoints",
"WeightOptions"
],
{
@ -36486,7 +36509,9 @@
[
"QwenImageEditScale",
"QwenImageEditSimpleScale",
"TextEncodeQwenImageEditAdv"
"TextEncodeQwenImageEditAdv",
"TextEncodeQwenImageEditInfAdv",
"TextEncodeQwenImageEditPlusAdv"
],
{
"title_aux": "comfyui_qwen_image_edit_adv"
@ -38480,6 +38505,7 @@
"EasyResize",
"EasyWan22Prompt",
"Easy_Version",
"KoolookLoadCameraPosesAbsolute",
"easy_ImageBatch"
],
{
@ -42821,6 +42847,12 @@
"WaveSpeedAI Flux Kontext Max",
"WaveSpeedAI Flux Kontext Pro",
"WaveSpeedAI Google Nano Banana Edit",
"WaveSpeedAI Google Nano Banana Pro Edit",
"WaveSpeedAI Google Nano Banana Pro Edit Multi",
"WaveSpeedAI Google Nano Banana Pro Edit Ultra",
"WaveSpeedAI Google Nano Banana Pro Text to Image",
"WaveSpeedAI Google Nano Banana Pro Text to Image Multi",
"WaveSpeedAI Google Nano Banana Pro Text to Image Ultra",
"WaveSpeedAI Google Nano Banana Text to Image",
"WaveSpeedAI Google VEO 3.1 Fast Image-to-Video",
"WaveSpeedAI Google VEO 3.1 Fast Text-to-Video",
@ -45260,8 +45292,11 @@
],
"https://github.com/smthemex/ComfyUI_DiffuEraser": [
[
"DiffuEraserLoader",
"DiffuEraserSampler"
"DiffuEraser_Loader",
"DiffuEraser_PreData",
"DiffuEraser_Sampler",
"Propainter_Loader",
"Propainter_Sampler"
],
{
"title_aux": "ComfyUI_DiffuEraser"

View File

@ -85,7 +85,15 @@ cm_global.register_api('cm.is_import_failed_extension', is_import_failed_extensi
comfyui_manager_path = os.path.abspath(os.path.dirname(__file__))
custom_nodes_base_path = folder_paths.get_folder_paths('custom_nodes')[0]
manager_files_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), 'default', 'ComfyUI-Manager'))
# Check for System User API availability (PR #10966)
_has_system_user_api = hasattr(folder_paths, 'get_system_user_directory')
if _has_system_user_api:
manager_files_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), '__manager'))
else:
manager_files_path = os.path.abspath(os.path.join(folder_paths.get_user_directory(), 'default', 'ComfyUI-Manager'))
manager_pip_overrides_path = os.path.join(manager_files_path, "pip_overrides.json")
manager_pip_blacklist_path = os.path.join(manager_files_path, "pip_blacklist.list")
restore_snapshot_path = os.path.join(manager_files_path, "startup-scripts", "restore-snapshot.json")
@ -516,7 +524,8 @@ check_bypass_ssl()
# Perform install
processed_install = set()
script_list_path = os.path.join(folder_paths.user_directory, "default", "ComfyUI-Manager", "startup-scripts", "install-scripts.txt")
# Use manager_files_path for consistency (fixes path inconsistency bug)
script_list_path = os.path.join(manager_files_path, "startup-scripts", "install-scripts.txt")
pip_fixer = manager_util.PIPFixer(manager_util.get_installed_packages(), comfy_path, manager_files_path)
@ -793,7 +802,11 @@ def execute_startup_script():
# Check if script_list_path exists
if os.path.exists(script_list_path):
# Block startup-scripts on old ComfyUI (security measure)
if not _has_system_user_api:
if os.path.exists(script_list_path):
print("[ComfyUI-Manager] Startup scripts blocked on old ComfyUI version.")
elif os.path.exists(script_list_path):
execute_startup_script()

View File

@ -1,7 +1,7 @@
[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.37.2"
version = "3.38"
license = { file = "LICENSE.txt" }
dependencies = ["GitPython", "PyGithub", "matrix-nio", "transformers", "huggingface-hub>0.20", "typer", "rich", "typing-extensions", "toml", "uv", "chardet"]