-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy path__init__.py
More file actions
760 lines (721 loc) · 31.9 KB
/
Copy path__init__.py
File metadata and controls
760 lines (721 loc) · 31.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
"""
ComfyUI-CustomNodePacks
=======================
A growing collection of custom nodes:
- FolderIncrementer – auto-incrementing version strings
- MaskEditControl – pinpoint mask editing, SAM2/SAM3, per-axis erode/expand,
point editing, bbox tools, video mask propagation,
alpha matting (ViTMatte / MatAnyone2)
- Universal Reroute – Nuke-style Dot node for clean wire management
- Parameter Memory – tracks every parameter change with history & defaults
"""
print("[MEC] Loading MaskEditControl node pack …")
# ── FolderIncrementer nodes ────────────────────────────────────────────
from .folder_incrementer import (
NODE_CLASS_MAPPINGS as _FOLDER_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _FOLDER_DISPLAY,
)
# ── Model Manager (shared cache / download) ───────────────────────────
from .nodes import model_manager as _model_manager # noqa: F401
# ── Live-preview guard: force sampling previews on even if launched with
# --preview-method none (Latent2RGB fallback, cannot fail). Best-effort. ──
try:
from .nodes import _c2c_preview_guard as _c2c_preview_guard # noqa: F401
except Exception: # never block the pack on a preview tweak
pass
# ── MaskEditControl nodes ─────────────────────────────────────────────
# Unified composition wrappers — these replace 12 legacy node classes:
# MaskEditMEC replaces MaskTransformXY, MaskDrawFrame, DrawShapeMEC,
# PointsMaskEditor, BBoxSmooth
# SplineMaskMEC replaces SplineMaskEditorMEC, SplineMaskTrackerMEC,
# SplinePathFlowMaskMEC
# MaskTrackerMEC replaces MotionMaskTrackerMEC, MaskPropagateVideo,
# TemporalAnchorMEC, TemporalConsistencyCheckerMEC
# The original source files remain on disk as internal implementation
# modules; they are imported by the unified wrappers via composition.
# No legacy NODE_CLASS_MAPPINGS entries are registered.
from .nodes.mask_edit_mec import MaskEditMEC
from .nodes.spline_mask_mec import SplineMaskMEC
from .nodes.mask_tracker_mec import MaskTrackerMEC
from .nodes.parameter_memory import ParameterHistoryMEC
from .nodes.sec_matanyone_pipeline import SeCMatAnyonePipelineMEC
from .nodes.inpaint_suite import (
InpaintCropProMEC,
InpaintStitchProMEC,
InpaintPasteBackMEC,
InpaintMaskPrepareMEC,
)
# VideoComparerC2C (renamed from VideoComparerMEC) replaces the deprecated
# ImageComparerMEC. The old image_comparer.py is retained on disk as an
# importable helper (ImageComparerMEC class), but only VideoComparerC2C is
# registered — with "VideoComparerMEC" kept as a back-compat alias key so
# saved workflows still load.
from .nodes.video_comparer import VideoComparerC2C
from .nodes.video_frame_player import VideoFramePlayerMEC
from .nodes.video_mask_editor import (
VideoMaskEditorMEC,
register_routes as _register_vme_routes,
)
from .nodes.vae_merge import VAEMergeMEC
from .nodes.vae_latent_inspector import VAELatentInspectorMEC
from .nodes.batch_version_manager import BatchVersionManagerMEC
from .nodes.model_metadata_extractor import ModelMetadataExtractorMEC
from .nodes.mask_failure_explainer import MaskFailureExplainerMEC
# ── MEC Paint Suite (Advanced Paint Canvas + Fixer + Refiner + Builder) ───
from .nodes.mec_paint_suite import (
NODE_CLASS_MAPPINGS as _PAINT_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _PAINT_DISPLAY,
)
# Face Fixer (auto YOLO11 detection + per-face KSampler + smart blend)
from .nodes.mec_face_fixer import (
NODE_CLASS_MAPPINGS as _FACE_FIXER_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _FACE_FIXER_DISPLAY,
)
# Face/Pose Delta Editor (anchor-relative landmark deltas, multi-keyframe)
try:
from .nodes.face_pose_delta import (
NODE_CLASS_MAPPINGS as _FPDELTA_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _FPDELTA_DISPLAY,
)
except Exception as _fpd_exc: # pragma: no cover
_FPDELTA_MAPPINGS, _FPDELTA_DISPLAY = {}, {}
try:
from .nodes._c2c_registry import record_failure as _c2c_rec_fail_fpd
_c2c_rec_fail_fpd(
"face_pose_delta", _fpd_exc,
hint="Face/Pose Delta Editor failed to import. "
"Ensure NumPy is installed and temporal_anchor.py is intact.",
group="nodes",
)
except Exception:
import logging as _lg
_lg.getLogger("MEC").warning(
"[MEC] face_pose_delta import failed: %s", _fpd_exc,
)
# Mask + Matting (multi-backend: SAM2.1, SAM3 + ViTMatte, RVM, ...)
# Guarded: a failure inside mask_matting (e.g. a missing _reanchor.py helper
# on an out-of-sync install) must NOT abort this __init__ — that would drop
# every other node in the pack (NanoBanana, WanDirector, OmniPill, Wizard…).
try:
from .nodes.mask_matting import (
NODE_CLASS_MAPPINGS as _MASKMATTE_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _MASKMATTE_DISPLAY,
)
except Exception as _mm_exc: # pragma: no cover
_MASKMATTE_MAPPINGS, _MASKMATTE_DISPLAY = {}, {}
try:
from .nodes._c2c_registry import record_failure as _c2c_rec_fail_mm
_c2c_rec_fail_mm(
"mask_matting", _mm_exc,
hint="Mask+Matting pack failed to import. Ensure "
"nodes/mask_matting/_reanchor.py is present and "
"opencv-python / transformers are installed.",
group="nodes",
)
except Exception:
import logging as _lg
_lg.getLogger("MEC").warning(
"[MEC] mask_matting import failed: %s", _mm_exc,
)
# ── Central failure registry (surface silent drops to the user) ───────
# Per ideas_summary.md §2.1: the #1 reason this pack "feels like stubs"
# is that optional sub-imports were swallowed by `except: pass` / quiet
# logger.debug() calls. From here on every optional-import block routes
# its failure through _c2c_registry.record_failure() so the user sees
# (a) a console line in the ComfyUI log, (b) a boot toast in the UI, and
# (c) a queryable /c2c/registry/status endpoint listing every miss with
# an actionable hint.
try:
from .nodes._c2c_registry import (
record_failure as _c2c_rec_fail,
register_routes as _c2c_reg_register_routes,
)
except Exception as _reg_exc: # pragma: no cover
import logging
logging.getLogger("C2C").error(
"c2c registry helper missing — falling back to plain logging: %s", _reg_exc
)
def _c2c_rec_fail(key, exc, *, hint=None, group="root", severity="warning"): # type: ignore
import logging
logging.getLogger("C2C").warning("%s unavailable: %s (hint=%s)", key, exc, hint)
def _c2c_reg_register_routes(_server): # type: ignore
return None
# Unified Segmentation — DEPRECATED (superseded by mask_matting + sam_model_loader
# + sam_mask_generator). The file is kept on disk for reference only.
_USEG_MAPPINGS, _USEG_DISPLAY = {}, {}
# SAM Model Loader + Mask Generator (standalone SAM2.1/SAM3 inference nodes)
try:
from .nodes.sam_model_loader import SAMModelLoaderMEC
from .nodes.sam_mask_generator import SAMMaskGeneratorMEC
_SAM_MAPPINGS = {
"SAMModelLoaderMEC": SAMModelLoaderMEC,
"SAMMaskGeneratorMEC": SAMMaskGeneratorMEC,
}
_SAM_DISPLAY = {
"SAMModelLoaderMEC": "SAM Model Loader \u2014 SAM2.1 / SAM3",
"SAMMaskGeneratorMEC": "SAM Mask Generator \u2014 Points + BBox + Text",
}
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"SAM Loader/Generator", _exc,
hint="SAM nodes require the sam2 package and model weights under models/sam2/.",
group="nodes",
)
_SAM_MAPPINGS, _SAM_DISPLAY = {}, {}
# SAM + ViTMatte combined pipeline (highest-quality mask in one node)
try:
from .nodes.sam_vitmatte_pipeline import SAMViTMattePipelineMEC
_SAMVIT_MAPPINGS = {"SAMViTMattePipelineMEC": SAMViTMattePipelineMEC}
_SAMVIT_DISPLAY = {
"SAMViTMattePipelineMEC": "SAM + ViTMatte Pipeline \u2014 Full Quality",
}
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"SAMViTMattePipeline", _exc,
hint="Requires sam2 package + transformers for ViTMatte refinement.",
group="nodes",
)
_SAMVIT_MAPPINGS, _SAMVIT_DISPLAY = {}, {}
# Luminance Keyer (Nuke-style luma key, pure tensor math)
try:
from .nodes.luminance_keyer import LuminanceKeyerMEC
_LUMAKEY_MAPPINGS = {"LuminanceKeyerMEC": LuminanceKeyerMEC}
_LUMAKEY_DISPLAY = {
"LuminanceKeyerMEC": "Luminance Keyer \u2014 Highlights / Shadows / Custom",
}
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"LuminanceKeyer", _exc,
hint="Luminance Keyer failed to import — check _interrupt_check / _progress helpers.",
group="nodes",
)
_LUMAKEY_MAPPINGS, _LUMAKEY_DISPLAY = {}, {}
# Background Remover (RMBG-2.0 / BiRefNet one-click bg removal)
try:
from .nodes.background_remover import BackgroundRemoverMEC
_BGREMOVE_MAPPINGS = {"BackgroundRemoverMEC": BackgroundRemoverMEC}
_BGREMOVE_DISPLAY = {
"BackgroundRemoverMEC": "Background Remover \u2014 RMBG / BiRefNet",
}
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"BackgroundRemover", _exc,
hint="Requires transformers + model weights for RMBG or BiRefNet.",
group="nodes",
)
_BGREMOVE_MAPPINGS, _BGREMOVE_DISPLAY = {}, {}
# Semantic Segment (SegFormer face / clothes parsing)
try:
from .nodes.semantic_segment import SemanticSegmentMEC
_SEMSEG_MAPPINGS = {"SemanticSegmentMEC": SemanticSegmentMEC}
_SEMSEG_DISPLAY = {
"SemanticSegmentMEC": "Semantic Segment \u2014 Face / Clothes Parsing",
}
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"SemanticSegment", _exc,
hint="Requires transformers + SegFormer model weights.",
group="nodes",
)
_SEMSEG_MAPPINGS, _SEMSEG_DISPLAY = {}, {}
# SAM Multi-Mask Picker — interactive 3-thumbnail mask chooser
# (user-recalled feature: pick best of N SAM candidates by score)
try:
from .nodes.sam_multi_mask_picker import SamMultiMaskPickerMEC
_SAMPICKER_MAPPINGS = {"SamMultiMaskPickerMEC": SamMultiMaskPickerMEC}
_SAMPICKER_DISPLAY = {
"SamMultiMaskPickerMEC": "SAM Multi-Mask Picker \u2014 3 candidates + scores",
}
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"SamMultiMaskPickerMEC", _exc,
hint="Install SAM (sam2 or segment-anything) so candidate masks can be scored.",
group="nodes",
)
_SAMPICKER_MAPPINGS, _SAMPICKER_DISPLAY = {}, {}
# Wan Director (P9) — multi-shot orchestration utilities
try:
from .nodes.wan_director import (
NODE_CLASS_MAPPINGS as _WANDIR_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _WANDIR_DISPLAY,
)
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"WanDirector", _exc,
hint="Install `av` (PyAV) for audio mixing and ensure Wan 2.x model nodes are available.",
group="nodes",
)
_WANDIR_MAPPINGS, _WANDIR_DISPLAY = {}, {}
# C2C helpers (12 tiny utilities)
try:
from .nodes.helpers import (
NODE_CLASS_MAPPINGS as _HELPERS_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _HELPERS_DISPLAY,
)
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"C2C helpers", _exc,
hint="Helper utilities should always load — report this traceback as a bug.",
group="nodes", severity="error",
)
_HELPERS_MAPPINGS, _HELPERS_DISPLAY = {}, {}
# Prompt Relay — refined port (native + Kijai + generic-fallback backends).
# Algorithm credit: Gordon Chen & contributors. See nodes/prompt_relay/NOTICE.md.
try:
from .nodes.prompt_relay import (
NODE_CLASS_MAPPINGS as _PROMPTRELAY_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _PROMPTRELAY_DISPLAY,
)
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"PromptRelay", _exc,
hint="Prompt Relay requires Wan 2.x or compatible video model nodes for full backends.",
group="nodes",
)
_PROMPTRELAY_MAPPINGS, _PROMPTRELAY_DISPLAY = {}, {}
# AsymFlow sampler patch — Apache-2.0; algorithm by Lakonik/LakonLab.
try:
from .nodes.asymflow_sampler import (
NODE_CLASS_MAPPINGS as _ASYMFLOW_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _ASYMFLOW_DISPLAY,
)
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"AsymFlow sampler", _exc,
hint="AsymFlow patches ComfyUI's sampler module; a Comfy upgrade may have broken the patch surface.",
group="nodes",
)
_ASYMFLOW_MAPPINGS, _ASYMFLOW_DISPLAY = {}, {}
# HDR Color Science nodes (ACES tonemap, VAE quality decode, color space)
try:
from .nodes.hdr_color_science import (
NODE_CLASS_MAPPINGS as _HDR_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _HDR_DISPLAY,
)
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"HDR Color Science", _exc,
hint="HDR color science nodes for ACES tonemap, VAE quality decode, and color space conversion.",
group="nodes",
)
_HDR_MAPPINGS, _HDR_DISPLAY = {}, {}
# LocateAnything-3B grounding (open-vocabulary object detection → SAM prompts)
try:
from .nodes.locate_anything import (
NODE_CLASS_MAPPINGS as _LOCATE_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _LOCATE_DISPLAY,
)
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"LocateAnything", _exc,
hint="Requires transformers + nvidia/LocateAnything-3B weights for open-vocabulary grounding.",
group="nodes",
)
_LOCATE_MAPPINGS, _LOCATE_DISPLAY = {}, {}
# Nano Banana (Google Gemini image API: gemini-3-pro-image + 2.5-flash-image)
try:
from .nodes.nano_banana import (
NODE_CLASS_MAPPINGS as _NANOBANANA_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _NANOBANANA_DISPLAY,
)
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"NanoBanana", _exc,
hint="Gemini image-generation node; needs only stdlib + PIL + a GEMINI_API_KEY.",
group="nodes",
)
_NANOBANANA_MAPPINGS, _NANOBANANA_DISPLAY = {}, {}
# LocateAnything-3B grounding (open-vocabulary detection → SAM prompts)
try:
from .nodes.locate_anything import (
NODE_CLASS_MAPPINGS as _LOCATE_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _LOCATE_DISPLAY,
)
except Exception as _exc: # pragma: no cover
import logging
logging.getLogger("MEC.LocateAnything").warning(
"LocateAnything unavailable: %s", _exc
)
_LOCATE_MAPPINGS, _LOCATE_DISPLAY = {}, {}
# ── NukeNodeMax suite (P0..F7) ────────────────────────────────────────
# ── ProPainter unified dispatcher (absorbs Temporal/Remove/Stitch/StitchRefine/FlowRefine) ──
# Helper source files are kept on disk as importable Python classes; only
# ProPainterMEC is registered here.
from .nodes.propainter_unified import ProPainterMEC
from .nodes.video_stabilizer_mec import (
NODE_CLASS_MAPPINGS as _STABILIZER_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _STABILIZER_DISPLAY,
)
# NOTE: The following node families now live EXCLUSIVELY in
# ComfyUI-NukeMaxNodes (May 2026 migration) to avoid duplicate functionality
# and divergent type semantics. The MEC copies have been moved to _deprecated/.
# - Deep* (DeepFromImage / DeepMerge / DeepHoldout / DeepComposite)
# - Roto (VectorRotoMEC -> NukeMax_RotoSplineEditor + suite)
# - Shuffle (ShuffleMEC -> NukeMax_ShuffleImage / NukeMax_ShuffleLatent)
# - Flow (OpticalFlowMEC -> NukeMax_ComputeOpticalFlow + warps)
# - Tcl/Nk (TclSerialize/Parse -> NukeMax_NkScriptSerialize / Parse)
# FlowRefineMEC (post-flow inpainting prep) is kept here because it is part of
# the ProPainter pipeline, not a generic Nuke flow utility.
from .nodes.insight import InsightStatusMEC, install as _install_insight_hook
from .nodes.integrity_guard import (
IntegrityStatusMEC,
register_routes as _register_integrity_routes,
start_background_scan as _start_integrity_scan,
)
_NUKEMAX_MAPPINGS = {
"ProPainterMEC": ProPainterMEC,
"InsightStatusMEC": InsightStatusMEC,
"IntegrityStatusMEC": IntegrityStatusMEC,
}
_NUKEMAX_DISPLAY = {
"ProPainterMEC": "ProPainter \u2014 Temporal / Remove / Stitch / Refine / Flow",
"InsightStatusMEC": "Insight Status",
"IntegrityStatusMEC": "Integrity Status",
}
# ── VFX nodes migrated to ComfyUI-NukeMaxNodes (Apr 2026) ─────────────
# (color_science, exr_io, render_pass, plate_tools, geometry_nodes,
# metadata_nodes, exr_metadata_reader, universal_reroute)
# Model analysis stays here:
from .nodes.model_analysis import (
NODE_CLASS_MAPPINGS as _MA_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _MA_DISPLAY,
)
# Legacy mask refinement suite (DenseCRF / Guided / Thin / QualityScore / Trimap)
# is fully replaced by the single ``MaskRefineMEC`` node registered via
# ``mask_matting`` package — no separate registration here.
_MEC_MAPPINGS = {
"MaskEditMEC": MaskEditMEC,
"SplineMaskMEC": SplineMaskMEC,
"MaskTrackerMEC": MaskTrackerMEC,
"ParameterHistoryMEC": ParameterHistoryMEC,
"SeCMatAnyonePipelineMEC": SeCMatAnyonePipelineMEC,
"InpaintCropProMEC": InpaintCropProMEC,
"InpaintStitchProMEC": InpaintStitchProMEC,
"InpaintPasteBackMEC": InpaintPasteBackMEC,
"InpaintMaskPrepareMEC": InpaintMaskPrepareMEC,
"VideoComparerC2C": VideoComparerC2C,
# NOTE: "VideoComparerMEC" was the legacy class key. To prevent it from
# showing up as a separate (duplicate) entry in the node search palette,
# it is NO LONGER registered here. Saved workflows that reference the old
# type are migrated at graph-load time by js/video_comparer_c2c.js, which
# rewrites `type: "VideoComparerMEC"` -> `"VideoComparerC2C"` before
# LiteGraph instantiates the node.
"VideoFramePlayerMEC": VideoFramePlayerMEC,
"VideoMaskEditorMEC": VideoMaskEditorMEC,
"VAEMergeMEC": VAEMergeMEC,
"VAELatentInspectorMEC": VAELatentInspectorMEC,
"BatchVersionManagerMEC": BatchVersionManagerMEC,
"ModelMetadataExtractorMEC": ModelMetadataExtractorMEC,
"MaskFailureExplainerMEC": MaskFailureExplainerMEC,
}
_MEC_DISPLAY = {
"MaskEditMEC": "Mask Edit \u2014 Transform/Draw/Points/BBox",
"SplineMaskMEC": "Spline Mask \u2014 Edit/Track/Flow-Path",
"MaskTrackerMEC": "Mask Tracker \u2014 Motion/Propagate/Anchor/Consistency",
"ParameterHistoryMEC": "Parameter History",
"SeCMatAnyonePipelineMEC": "SeC + MatAnyone2 Pipeline",
"InpaintCropProMEC": "Inpaint Crop Pro",
"InpaintStitchProMEC": "Inpaint Stitch Pro",
"InpaintPasteBackMEC": "Inpaint Paste Back",
"InpaintMaskPrepareMEC": "Inpaint Mask Prepare",
"VideoComparerC2C": "Video Comparer \u2014 Player + Wipe/Diff/Scopes",
"VideoFramePlayerMEC": "Video Frame Player",
"VideoMaskEditorMEC": "Video Mask Editor",
"VAEMergeMEC": "VAE Merge",
"VAELatentInspectorMEC": "VAE Latent Inspector",
"BatchVersionManagerMEC": "Batch Version Manager",
"ModelMetadataExtractorMEC": "Model Metadata Extractor",
"MaskFailureExplainerMEC": "Mask Failure Explainer \u2014 Diagnostics",
}
# ── Merge all mappings ────────────────────────────────────────────────
try:
from .nodes.control_forge import (
NODE_CLASS_MAPPINGS as _CONTROLFORGE_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _CONTROLFORGE_DISPLAY,
)
except Exception as _cf_exc: # pragma: no cover
try:
_c2c_rec_fail("Control AOV", _cf_exc,
hint="control_forge needs numpy + torch (OpenCV optional for Canny/motion).",
group="nodes")
except Exception:
pass
_CONTROLFORGE_MAPPINGS, _CONTROLFORGE_DISPLAY = {}, {}
# Clipboard TCL — Nuke-style copy/paste of node graphs (F5). Restored 2026-06-20
# (was removed in a 2026-05 "deprecated cleanup"; it has no replacement).
try:
from .nodes.clipboard_tcl import (
NODE_CLASS_MAPPINGS as _TCL_MAPPINGS,
NODE_DISPLAY_NAME_MAPPINGS as _TCL_DISPLAY,
register_routes as _register_tcl_routes,
)
except Exception as _exc: # pragma: no cover
_c2c_rec_fail(
"ClipboardTCL", _exc,
hint="Nuke-style TCL copy/paste of node graphs (F5); stdlib only.",
group="nodes",
)
_TCL_MAPPINGS, _TCL_DISPLAY = {}, {}
def _register_tcl_routes(_server): # type: ignore
return None
# ── Restored VFX / utility nodes (removed in a 2026-05 "deprecated cleanup";
# verified they have NO replacement in the current pack, so brought back).
# Each module is guarded independently so one failure never drops the rest.
_RESTORED_MAPPINGS, _RESTORED_DISPLAY = {}, {}
for _rmod in ("color_science", "exr_io", "exr_metadata_reader", "geometry_nodes",
"metadata_nodes", "plate_tools", "render_pass", "video_frame_extractor",
"optical_flow", "roto", "shuffle"):
try:
_rm = __import__(f"{__name__}.nodes.{_rmod}", fromlist=["NODE_CLASS_MAPPINGS"])
_RESTORED_MAPPINGS.update(getattr(_rm, "NODE_CLASS_MAPPINGS", {}) or {})
_RESTORED_DISPLAY.update(getattr(_rm, "NODE_DISPLAY_NAME_MAPPINGS", {}) or {})
except Exception as _rexc: # pragma: no cover
_c2c_rec_fail(
f"restored:{_rmod}", _rexc,
hint="VFX/utility node restored from git history; may need cv2/OpenEXR.",
group="nodes",
)
NODE_CLASS_MAPPINGS = {
**_FOLDER_MAPPINGS,
**_MEC_MAPPINGS,
**_MA_MAPPINGS,
**_PAINT_MAPPINGS,
**_FACE_FIXER_MAPPINGS,
**_FPDELTA_MAPPINGS,
**_MASKMATTE_MAPPINGS,
**_USEG_MAPPINGS,
**_SAMPICKER_MAPPINGS,
**_SAM_MAPPINGS,
**_SAMVIT_MAPPINGS,
**_LUMAKEY_MAPPINGS,
**_BGREMOVE_MAPPINGS,
**_SEMSEG_MAPPINGS,
**_NUKEMAX_MAPPINGS,
**_STABILIZER_MAPPINGS,
**_WANDIR_MAPPINGS,
**_HELPERS_MAPPINGS,
**_PROMPTRELAY_MAPPINGS,
**_ASYMFLOW_MAPPINGS,
**_HDR_MAPPINGS,
**_LOCATE_MAPPINGS,
**_NANOBANANA_MAPPINGS,
**_CONTROLFORGE_MAPPINGS,
**_TCL_MAPPINGS,
**_RESTORED_MAPPINGS,
}
NODE_DISPLAY_NAME_MAPPINGS = {
**_FOLDER_DISPLAY,
**_MEC_DISPLAY,
**_MA_DISPLAY,
**_PAINT_DISPLAY,
**_FACE_FIXER_DISPLAY,
**_FPDELTA_DISPLAY,
**_MASKMATTE_DISPLAY,
**_USEG_DISPLAY,
**_SAMPICKER_DISPLAY,
**_SAM_DISPLAY,
**_SAMVIT_DISPLAY,
**_LUMAKEY_DISPLAY,
**_BGREMOVE_DISPLAY,
**_SEMSEG_DISPLAY,
**_NUKEMAX_DISPLAY,
**_STABILIZER_DISPLAY,
**_WANDIR_DISPLAY,
**_HELPERS_DISPLAY,
**_PROMPTRELAY_DISPLAY,
**_ASYMFLOW_DISPLAY,
**_HDR_DISPLAY,
**_LOCATE_DISPLAY,
**_NANOBANANA_DISPLAY,
**_CONTROLFORGE_DISPLAY,
**_TCL_DISPLAY,
**_RESTORED_DISPLAY,
}
WEB_DIRECTORY = "./js"
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
# ── Register server routes for Parameter Memory ──────────────────────
try:
import server as _comfy_server
from .nodes.parameter_memory import register_routes as _register_pm_routes
_register_pm_routes(_comfy_server.PromptServer.instance)
print("[MEC] Parameter Memory server route registered.")
except Exception:
pass # Server not available (e.g. during import-only testing)
# ── Register server routes for Video Mask Editor ─────────────────────
try:
import server as _comfy_server_vme
_register_vme_routes(_comfy_server_vme.PromptServer.instance)
except Exception:
pass # Server not available
# ── Register Clipboard TCL (Nuke-style copy/paste) routes ────────────
try:
import server as _comfy_server_tcl
_register_tcl_routes(_comfy_server_tcl.PromptServer.instance)
print("[MEC] Clipboard TCL (Nuke-style copy/paste) routes registered.")
except Exception:
pass # Server not available
# ── Register NukeNodeMax server-side hooks & routes ───────────────────
try:
import server as _comfy_server # noqa: F811
_ps = _comfy_server.PromptServer.instance
# Surface the central failure registry FIRST so it's queryable even if
# everything below fails to register.
try:
_c2c_reg_register_routes(_ps)
except Exception as _re:
print(f"[C2C] registry routes deferred: {_re}")
_register_integrity_routes(_ps)
_start_integrity_scan()
_install_insight_hook()
try:
from .nodes.mec_diagnostics_api import (
register_routes as _register_mec_diag_routes,
install_insight_bridge as _install_mec_diag_bridge,
)
_register_mec_diag_routes(_ps)
_install_mec_diag_bridge()
print("[MEC] mec_diagnostics sidebar API registered.")
except Exception as _diag_e:
print(f"[MEC] mec_diagnostics deferred: {_diag_e}")
try:
from .nodes.node_explain import register_routes as _register_node_explain_routes
_register_node_explain_routes(_ps)
print("[MEC] node_explain routes registered.")
except Exception as _ne:
print(f"[MEC] node_explain deferred: {_ne}")
try:
from .nodes.error_translator import register_routes as _register_error_translator_routes
_register_error_translator_routes(_ps)
print("[MEC] error_translator routes registered.")
except Exception as _et:
print(f"[MEC] error_translator deferred: {_et}")
try:
from .nodes.error_introspector import register_routes as _register_error_introspector_routes
_register_error_introspector_routes(_ps)
print("[MEC] error_introspector routes registered.")
except Exception as _ei:
print(f"[MEC] error_introspector deferred: {_ei}")
try:
from .nodes.flamegraph import register_routes as _register_flamegraph_routes
_register_flamegraph_routes(_ps)
print("[MEC] flamegraph routes registered.")
except Exception as _fg:
print(f"[MEC] flamegraph deferred: {_fg}")
try:
from .nodes.tensor_inspector import register_routes as _register_tensor_inspector_routes
_register_tensor_inspector_routes(_ps)
print("[MEC] tensor_inspector routes registered.")
except Exception as _ti:
print(f"[MEC] tensor_inspector deferred: {_ti}")
try:
from .nodes.token_counter import register_routes as _register_token_counter_routes
_register_token_counter_routes(_ps)
print("[MEC] token_counter routes registered.")
except Exception as _tc:
print(f"[MEC] token_counter deferred: {_tc}")
try:
from .nodes.group_presets import register_routes as _register_group_presets_routes
_register_group_presets_routes(_ps)
print("[MEC] group_presets routes registered.")
except Exception as _gp:
print(f"[MEC] group_presets deferred: {_gp}")
try:
from .nodes.cost_estimator import register_routes as _register_cost_estimator_routes
_register_cost_estimator_routes(_ps)
print("[MEC] cost_estimator routes registered.")
except Exception as _ce:
print(f"[MEC] cost_estimator deferred: {_ce}")
try:
from .nodes.wizard import register_routes as _register_wizard_routes
_register_wizard_routes(_ps)
print("[MEC] wizard routes registered.")
except Exception as _wz:
print(f"[MEC] wizard deferred: {_wz}")
try:
from .nodes.workflow_doctor import register_routes as _register_workflow_doctor_routes
_register_workflow_doctor_routes(_ps)
print("[C2C] workflow_doctor routes registered.")
except Exception as _wd:
print(f"[C2C] workflow_doctor deferred: {_wd}")
try:
from .nodes.c2c_int_aggregator import register_routes as _register_c2c_int_routes
_register_c2c_int_routes(_ps)
print("[C2C] int aggregator routes registered (/c2c/int/*).")
except Exception as _int:
print(f"[C2C] int aggregator deferred: {_int}")
try:
from .nodes.c2c_doctor import register_routes as _register_c2c_doctor_routes
_register_c2c_doctor_routes(_ps)
print("[C2C] doctor routes registered (/c2c/doctor/{pyenv,disk,scan_file}).")
except Exception as _doc:
print(f"[C2C] doctor deferred: {_doc}")
try:
from .nodes.c2c_workflow_library import register_routes as _register_c2c_library_routes
_register_c2c_library_routes(_ps)
print("[C2C] workflow library routes registered (/c2c/library/{locations,scan,load}).")
except Exception as _lib:
print(f"[C2C] workflow library deferred: {_lib}")
try:
from .nodes._c2c_autoconnect import register_routes as _register_c2c_autoconnect_routes
_register_c2c_autoconnect_routes(_ps)
print("[C2C] autoconnect routes registered (/c2c/autoconnect/*).")
except Exception as _ac:
print(f"[C2C] autoconnect deferred: {_ac}")
try:
from .nodes.c2c_sys_metrics import register_routes as _register_c2c_sys_metrics_routes
_register_c2c_sys_metrics_routes(_ps)
print("[C2C] sys metrics routes registered (/c2c/sys/metrics).")
except Exception as _sm:
print(f"[C2C] sys metrics deferred: {_sm}")
try:
from .nodes._c2c_secrets import register_routes as _register_c2c_secrets_routes, backend_name as _c2c_secrets_backend
_register_c2c_secrets_routes(_ps)
print(f"[C2C] secrets vault routes registered (/c2c/secrets/*) backend={_c2c_secrets_backend()}.")
except Exception as _sec:
print(f"[C2C] secrets vault deferred: {_sec}")
try:
from .nodes.style_presets import register_routes as _register_style_presets_routes
_register_style_presets_routes(_ps)
print("[C2C] style_presets routes registered.")
except Exception as _sp:
print(f"[C2C] style_presets deferred: {_sp}")
# ── C2C Preset Hub (live aggregator: lexica/civitai/hf/openart/pdexter/issues) ─
try:
from .nodes._c2c_preset_hub import register_routes as _register_preset_hub_routes
_register_preset_hub_routes(_ps)
print("[C2C] preset hub routes registered (/c2c/presets/*).")
except Exception as _ph:
print(f"[C2C] preset hub deferred: {_ph}")
try:
from .nodes.mask_matting.integrity_bridge import register_routes as _register_integrity_bridge_routes
_register_integrity_bridge_routes(_ps)
print("[C2C] mask_integrity bridge routes registered.")
except Exception as _ib:
print(f"[C2C] mask_integrity bridge deferred: {_ib}")
# ── C2C AI spine (v2.0-dev) ────────────────────────────────────
try:
from .c2c_ai.api_routes import register_routes as _register_c2c_ai_routes
from .c2c_ai.bootstrap import bootstrap as _c2c_ai_bootstrap
_register_c2c_ai_routes(_ps)
_c2c_ai_bootstrap()
print("[C2C AI] spine registered (/c2c/ai/*).")
except Exception as _ai:
print(f"[C2C AI] spine deferred: {_ai}")
# ── C2C prompt library (Gallery sources: lexica today; civitai/openart next) ─
try:
from .c2c_ai.prompt_library import register_routes as _register_c2c_prompts_routes
_register_c2c_prompts_routes(_ps)
print("[C2C AI] prompt library registered (/c2c/prompts/*).")
except Exception as _pl:
print(f"[C2C AI] prompt library deferred: {_pl}")
# ── C2C dep-conflict checker (Manager integration) ─────────────
try:
from .nodes.dep_check_routes import register_routes as _register_depcheck_routes
_register_depcheck_routes(_ps)
print("[C2C] depcheck routes registered (/c2c/depcheck/*).")
except Exception as _dc:
print(f"[C2C] depcheck routes deferred: {_dc}")
print("[MEC] NukeNodeMax routes + hooks registered.")
except Exception as _e:
print(f"[MEC] NukeNodeMax server hooks deferred: {_e}")
print(f"[MEC] Loaded {len(_MEC_MAPPINGS)} MaskEditControl nodes.")