v2.2.0: Prompt Builder nodes, wildcard review tool, docs refresh

- Add Wildcard Prompt Composer and Wildcard Character Composer builder nodes (core/builder, web/prompt_builder.js, builders/, vp wildcard lists)

- Add browser-based wildcard review tool (tools/wildcard_review) with manifest-based undo

- Add wildcard catalog/curation, surreal compiler/lint/scene, profile token budget

- README: document all 18 nodes, bump to v2.2.0, fix stale node/platform lists; CHANGELOG 2.2.0

- Rewrite NODE_COMPARISON for 18 nodes; fix QUICKSTART (dead test_setup.py ref, menu path) and QUICK_REFERENCE node list

- gitignore review manifests and CLAUDE.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Eric Hiss
2026-10-28 20:36:44 -07:00
co-authored by Copilot
parent df90d119b4
commit 373ea8bda3
81 changed files with 15705 additions and 588 deletions
+13 -1
View File
@@ -27,7 +27,7 @@ import traceback
from typing import Tuple
from .core.wildcards import MODES, split_paths
from .wildcard_support import database_provider, get_wildcard_engine
from .wildcard_support import database_provider, get_wildcard_engine, wildcard_nsfw_input
class WildcardProcessor:
@@ -76,6 +76,8 @@ class WildcardProcessor:
"default": "",
"tooltip": "Extra wildcard folders, one per line, highest priority. ComfyUI/models/wildcards is always searched; this is for folders elsewhere.",
}),
# New inputs are only ever APPENDED below this line, so saved workflows keep their widget order.
**wildcard_nsfw_input(),
},
}
@@ -93,6 +95,8 @@ class WildcardProcessor:
legacy_syntax: bool = True,
use_prompt_database: bool = True,
extra_paths: str = "",
nsfw: str = "off",
violence_filter: str = "off",
) -> Tuple[str, str, str, str]:
try:
engine = get_wildcard_engine(split_paths(extra_paths))
@@ -105,6 +109,8 @@ class WildcardProcessor:
cycle_index=int(index),
legacy=bool(legacy_syntax),
providers=providers,
nsfw=nsfw,
violence=violence_filter,
)
report_lines = [resolution.summary()]
@@ -113,6 +119,12 @@ class WildcardProcessor:
f"combination {int(index) % max(1, resolution.combination_space) + 1} of {resolution.combination_space}"
)
report_lines.append("search folders: " + "; ".join(engine.library.search_paths))
library = engine.library
report_lines.append(
f"NSFW level: {nsfw}; lookup: {library.pool_mode}; "
f"entries removed by the content filter so far: {library.blocked_entries}; "
f"LoRA tags stripped so far: {library.stripped_lora_tags}"
)
return (
resolution.text,