Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
667 commits
Select commit Hold shift + click to select a range
585e7dd
Initial plan
Copilot Nov 26, 2025
e710ae5
Address code review feedback: consolidate logic, clarify comments, ex…
Copilot Nov 26, 2025
fb4f683
Fix incomplete comment in pathresolve.py
Copilot Nov 26, 2025
40dc868
Merge pull request #70 from xxmjskxx/copilot/sub-pr-64
Mossbraker Nov 26, 2025
9ce8a9c
Initial plan
Copilot Nov 26, 2025
348a500
Corrections to Copilot instruction files
Mossbraker Nov 26, 2025
208cd2b
Merge branch 'non-descriptive-names-fix' of https://github.com/xxmjsk…
Mossbraker Nov 26, 2025
746ef6f
Address code review feedback: improve comments, fix duplicate handlin…
Copilot Nov 26, 2025
70d5444
Clarify model strength validation comment to explain None check intent
Copilot Nov 26, 2025
8b4fa17
Enhance docstring for _parse_top_level_entries
Mossbraker Nov 26, 2025
84aa156
Fix formatting in rules_save.py example
Mossbraker Nov 26, 2025
ca7a7e9
Merge pull request #71 from xxmjskxx/copilot/sub-pr-64
Mossbraker Nov 26, 2025
fef0697
Initial plan
Copilot Nov 26, 2025
88931c7
Address PR review feedback: pure functions, descriptive names, DRY he…
Copilot Nov 26, 2025
20f2a40
Merge pull request #72 from xxmjskxx/copilot/sub-pr-64
Mossbraker Nov 26, 2025
e6ae908
Update comment on random seed generation length
Mossbraker Nov 26, 2025
3b32780
Initial plan
Copilot Nov 26, 2025
47ccf14
Address PR review feedback: fix truthiness checks and cycle detection
Copilot Nov 26, 2025
0842dab
Merge pull request #73 from xxmjskxx/copilot/sub-pr-64
Mossbraker Nov 26, 2025
aa710cd
Remove sampler formatting from capture.py for non-civitai (default) s…
Mossbraker Nov 26, 2025
9b93dec
Fix validation_metadata.py
Mossbraker Nov 26, 2025
b59c24d
Get validate_metadata.py working with webp again
Mossbraker Nov 26, 2025
2d86aa8
- Routed `extract_embedding_hashes` through `_hash_file`, so embeddin…
Mossbraker Nov 26, 2025
9d2947a
Initial plan
Copilot Nov 26, 2025
101e66c
Fix nested test function and add embedding metadata assertions
Copilot Nov 26, 2025
0562549
Merge pull request #74 from xxmjskxx/copilot/sub-pr-64
Mossbraker Nov 26, 2025
47bf051
Improve test coverage for utility functions and validators
Mossbraker Nov 26, 2025
73a94c3
**Capture Tests**
Mossbraker Nov 26, 2025
e36e989
Added test_capture_selectors_and_pnginfo.py (20 tests) covering:
Mossbraker Nov 26, 2025
4dd387f
The coverage has improved from 68.56% to **71%** overall. Let me also…
Mossbraker Nov 26, 2025
8ee1cd0
Add new tests to improve coverage of several modules
Mossbraker Nov 26, 2025
03a250d
1. **test_efficiency_helpers.py** - 45 tests for efficiency_nodes.py …
Mossbraker Nov 26, 2025
d093db3
Update tests/tools/validate_metadata.py
Mossbraker Nov 26, 2025
2b76ffa
Merge pull request #64 from xxmjskxx/non-descriptive-names-fix
Mossbraker Nov 26, 2025
e261a92
Initial plan
Copilot Nov 26, 2025
b0cdcb8
Address PR review feedback: DRY helper, test cleanup, improved imports
Copilot Nov 26, 2025
80d9a88
Merge pull request #76 from xxmjskxx/copilot/sub-pr-75
Mossbraker Nov 26, 2025
d516dcd
three new test files that target the modules for
Mossbraker Nov 26, 2025
aa0879b
Merge branch 'improve-test-coverage' of https://github.com/xxmjskxx/C…
Mossbraker Nov 26, 2025
dac0ea6
Update linked files in Readme
Mossbraker Nov 26, 2025
8d1f7f9
lint and remove unused imports from test files.
Mossbraker Nov 26, 2025
c951bcc
Merge pull request #75 from xxmjskxx/improve-test-coverage
Mossbraker Nov 26, 2025
15c7272
Validation script and tests: fix reverse validation checks for extra …
Mossbraker Nov 26, 2025
e9c0a9f
Validation script changes; update tests to align with new defaults an…
Mossbraker Nov 26, 2025
41056cb
Fix path resolution for quoted filenames with extensions
google-labs-jules[bot] Nov 27, 2025
95a975e
Improve test coverage for `saveimage_unimeta`
google-labs-jules[bot] Nov 28, 2025
c4373f0
Fix #78
AlissaSabre Jan 19, 2026
e87caf6
Add filtering for inactive loras and backward compatibility in tests
EnragedAntelope Jan 24, 2026
1910e98
Enhance LoraManager: Add active field checks and prevent text merge f…
EnragedAntelope Jan 24, 2026
116812d
Fixes a wrong import that works only during tests.
AlissaSabre Jan 25, 2026
c624905
Avoids LBYL to accept generously; input_data may be a tuple rather th…
AlissaSabre Jan 25, 2026
11250d3
Uses the selectors for Lora Loader Stack when processing Lora Loader …
AlissaSabre Jan 26, 2026
25c95c6
select_stack_by_prefix needs to accept a tuple (as well as a list) fo…
AlissaSabre Jan 26, 2026
5928ec6
They say writing "except Exception:" is a bad practice.
AlissaSabre Jan 26, 2026
d09c1c8
Adds tests for issue #85 (Civitai compatible lora strengths.)
AlissaSabre Jan 31, 2026
fd98248
Makes Capture.gen_parameters_str() work as in the production environm…
AlissaSabre Feb 1, 2026
1d2fc74
Adds tests of Capture.gen_pnginfo_dict() for issue #85.
AlissaSabre Feb 1, 2026
43421de
get() is better than subscription in assert.
AlissaSabre Feb 1, 2026
38c05ff
POC implementation of issue #85 fix.
AlissaSabre Feb 1, 2026
badd81b
Docstring for gen_civitai_lora_hashes_and_strengths and some comment.
AlissaSabre Feb 3, 2026
85a3e31
Removes reference to Hypernetwork from test; I believe it is just red…
AlissaSabre Feb 3, 2026
13cfcbf
Refactors the test for more legible test output.
AlissaSabre Feb 6, 2026
23bcb63
Refactors tests more for legibility of the source file.
AlissaSabre Feb 6, 2026
5f54b57
gen_pnginfo_dict creates lora strengths data, but it leaves them not …
AlissaSabre Feb 6, 2026
4250219
gen_parameters_str merges LoRA strengths into positive prompt if its …
AlissaSabre Feb 6, 2026
24e4368
ChatGPT _strongly_ recommends me to use monkeypatch.setenv to rewrite…
AlissaSabre Feb 6, 2026
c1ba3b4
Adds lora_strengths_in_prompt toggle to the Save Image node.
AlissaSabre Feb 6, 2026
7970705
Adds test for Save Image node's FUNCTION.
AlissaSabre Feb 7, 2026
cc3b4fe
Fixes a ruff error.
AlissaSabre Feb 8, 2026
c708272
Fix coroutine outputs error, incorporate upstream PRs, and harden cod…
claude Mar 15, 2026
9fc4123
Merge pull request #1 from EnragedAntelope/claude/fix-coroutine-outpu…
EnragedAntelope Mar 15, 2026
f201018
Add metadata support for Z-Sampler Turbo (ZImagePowerNodes)
claude Mar 16, 2026
1e7ac85
Merge pull request #2 from EnragedAntelope/claude/fix-metadata-saving…
EnragedAntelope Mar 16, 2026
f227db2
Initial plan
Copilot Mar 17, 2026
bd5c157
Consolidate quoted-filename test into test_pathresolve.py and remove …
Copilot Mar 17, 2026
bca948e
Merge pull request #96 from xxmjskxx/copilot/sub-pr-95
Mossbraker Mar 17, 2026
85a670d
Merge pull request #95 from xxmjskxx/bugfix-path-resolution-quoted-fi…
Mossbraker Mar 17, 2026
5143bdf
Initial plan
Copilot Mar 17, 2026
6af3f9a
Address PR review feedback: fix indentation, remove no-op test, impro…
Copilot Mar 17, 2026
3e84802
Merge pull request #99 from xxmjskxx/copilot/sub-pr-98
Mossbraker Mar 17, 2026
84fb992
Initial plan
Copilot Mar 17, 2026
6cb6f44
Initial plan
Copilot Mar 17, 2026
2e66535
Address PR review comments: fix import pattern, remove misleading com…
Copilot Mar 17, 2026
932662b
Fix CI failures: use patch.object() instead of string-based patch for…
Copilot Mar 17, 2026
ac62a13
Remove unused _rw_mod import from test_rules_writer_coverage.py
Copilot Mar 17, 2026
058ed1c
Merge pull request #100 from xxmjskxx/copilot/sub-pr-98
Mossbraker Mar 17, 2026
fc63f8d
Merge pull request #101 from xxmjskxx/copilot/sub-pr-97
Mossbraker Mar 17, 2026
406d019
Merge pull request #98 from xxmjskxx/improve-test-coverage
Mossbraker Mar 17, 2026
065af93
Initial plan
Copilot Mar 17, 2026
97fecd7
Fix case-insensitive LoRA dedup and remove unused MagicMock import
Copilot Mar 17, 2026
bc5a9d2
Merge pull request #102 from xxmjskxx/copilot/sub-pr-97
Mossbraker Mar 17, 2026
5c3d4e5
Merge pull request #97 from xxmjskxx/validation-script
Mossbraker Mar 17, 2026
8c12208
Merge pull request #80 from AlissaSabre/feature/fix-embedding-issue
Mossbraker Mar 17, 2026
d2109e3
Merge pull request #82 from AlissaSabre/feature/fix-rgthree-issue
Mossbraker Mar 17, 2026
360b04c
Merge pull request #84 from AlissaSabre/feature/fix-rgthree-issue-83
Mossbraker Mar 17, 2026
bfe973a
Merge pull request #86 from AlissaSabre/feature/fix-lora-strength-issue
Mossbraker Mar 17, 2026
54b9258
Initial plan
Copilot Mar 17, 2026
acb4f16
Initial plan
Copilot Mar 17, 2026
df566f8
Address PR review: narrow exception handling, support both token_weig…
Copilot Mar 17, 2026
3fc4512
Address all PR review comments: fix typo, imports, indentation, torch…
Copilot Mar 17, 2026
13f9458
Add debug logging for token_weights fallback and None input test cove…
Copilot Mar 17, 2026
208da1b
Merge pull request #105 from xxmjskxx/copilot/sub-pr-104
Mossbraker Mar 17, 2026
4cc209a
Merge pull request #106 from xxmjskxx/copilot/sub-pr-103
Mossbraker Mar 17, 2026
8d3a039
Merge pull request #104 from xxmjskxx/fix-issue-85
Mossbraker Mar 17, 2026
2b410b4
Initial plan
Copilot Mar 17, 2026
94a252f
Address review comments: fix typo, hash source, KeyError handling, pe…
Copilot Mar 17, 2026
80f93d8
Simplify get_lora_data: use explicit items() check instead of getattr…
Copilot Mar 17, 2026
0d349db
Merge pull request #107 from xxmjskxx/copilot/sub-pr-103
Mossbraker Mar 17, 2026
2cb2cbe
Merge pull request #103 from xxmjskxx/rprr
Mossbraker Mar 17, 2026
33835fa
Merge EnragedAntelope/master (PR #91) into coroutine
Mossbraker Mar 17, 2026
dd601d0
default include_lora_summary=False
Mossbraker Mar 17, 2026
065bbec
Initial plan
Copilot Mar 17, 2026
75dcc9b
Fix all review comments: skip_text_parsing, select_by_prefix guards, …
Copilot Mar 17, 2026
1e9749d
Merge pull request #109 from xxmjskxx/copilot/sub-pr-108
Mossbraker Mar 17, 2026
ff762ea
Initial plan
Copilot Mar 17, 2026
ba33d88
Align defaults and docstrings: suppress_missing_class_log=True, fix e…
Copilot Mar 17, 2026
a53ce2f
Merge pull request #110 from xxmjskxx/copilot/sub-pr-108
Mossbraker Mar 17, 2026
4737816
Merge pull request #108 from xxmjskxx/coroutine
Mossbraker Mar 17, 2026
af010e2
Update release information for v1.4.0
Mossbraker Mar 18, 2026
712392e
Fix formatting in latest release section of README
Mossbraker Mar 18, 2026
541fa5e
Initial plan
Copilot Mar 18, 2026
1afbbd9
Fix all-inactive LoRA text merge bug and gen_parameters_str in-place …
Copilot Mar 18, 2026
6d284d3
Merge pull request #112 from xxmjskxx/copilot/sub-pr-111
Mossbraker Mar 18, 2026
58300f1
Refactor type checks to use union syntax for list and tuple in select…
Mossbraker Mar 18, 2026
effcb31
Add n6 LoRA strength clip reference in test inputs
Mossbraker Mar 18, 2026
79ed67a
Refactor variable names for clarity in _find_node_id_by_class_type fu…
Mossbraker Mar 18, 2026
a6b26ab
Merge pull request #111 from xxmjskxx/fixing
Mossbraker Mar 18, 2026
5197305
reorder widgets in SaveImageWithMetaDataUniversal class for backward …
Mossbraker Mar 18, 2026
aa58d2a
bump version to 1.4.1 in pyproject.toml
Mossbraker Mar 18, 2026
a2cb67d
Merge pull request #113 from xxmjskxx/save-widget-hotfit
Mossbraker Mar 18, 2026
67255e4
Fix syntax error in SaveImageWithMetaDataUniversal class
Mossbraker Mar 18, 2026
d91c21e
Update save_mode choices in SaveCustomMetadataRules class to fix bug …
Mossbraker Mar 18, 2026
9f58eb2
Fix syntax error in SaveImageWithMetaDataUniversal class
Mossbraker Mar 18, 2026
2299526
Update save_mode choices in SaveCustomMetadataRules class to fix bug …
Mossbraker Mar 18, 2026
e146aad
Merge branch 'rules-writer-fix' of https://github.com/xxmjskxx/ComfyU…
Mossbraker Mar 18, 2026
030fd38
Merge pull request #114 from xxmjskxx/rules-writer-fix
Mossbraker Mar 18, 2026
ff4a897
Initial plan
Copilot Mar 19, 2026
6b688b5
Initial plan
Copilot Mar 19, 2026
7f67a48
Add TextEncodeQwenImageEditPlus support for prompt extraction
Copilot Mar 19, 2026
7c8a935
fix: detect negative prompt through CFGGuider in SamplerCustomAdvance…
Copilot Mar 19, 2026
112e2d4
test: add realistic inputs to DualCFGGuider and BasicGuider test fixt…
Copilot Mar 19, 2026
993095e
Add integration test for TextEncodeQwenImageEditPlus full capture path
Copilot Mar 19, 2026
601ec13
Add more guiders
Mossbraker Mar 19, 2026
6fbb577
Add new guider configurations to captures.py
Mossbraker Mar 19, 2026
c024148
Fix syntax error in Scheduled CFGGuider definition
Mossbraker Mar 19, 2026
c28cbc9
Fix syntax errors in samplers.py dictionary definitions
Mossbraker Mar 19, 2026
c40585e
Merge pull request #115 from xxmjskxx/copilot/fix-prompt-detection-issue
Mossbraker Mar 19, 2026
f98ea75
Merge branch 'PR-fixes' into copilot/fix-negative-prompt-detection
Mossbraker Mar 19, 2026
7d97ad9
docs: update samplers.py module docstring to cover GUIDERS, convert s…
Copilot Mar 19, 2026
69062e4
Merge pull request #116 from xxmjskxx/copilot/fix-negative-prompt-det…
Mossbraker Mar 19, 2026
86b1385
Initial plan
Copilot Mar 19, 2026
d9c87ac
Fix Prompt (LoraManager) not detected as text encoder for prompt capture
Copilot Mar 19, 2026
693a9da
Address code review: remove unused monkeypatch params, add clarifying…
Copilot Mar 19, 2026
0eab5a3
Fix test cleanup: save/restore CAPTURE_FIELD_LIST instead of uncondit…
Copilot Mar 19, 2026
02eea45
Merge pull request #117 from xxmjskxx/copilot/fix-prompt-text-saving-…
Mossbraker Mar 19, 2026
430ce1b
refactor: route prompt branches generically
Mossbraker Mar 19, 2026
9f2f3be
Merge pull request #119 from xxmjskxx/generic-conditioning-routing
Mossbraker Mar 19, 2026
8d400d6
docs: update README typo to specify usage of GitHub Copilot
Mossbraker Mar 19, 2026
88a8ba9
Initial plan
Copilot Mar 19, 2026
35ba590
fix: tighten validator link detection
Copilot Mar 19, 2026
e6e47bb
Merge branch 'PR-fixes' into copilot/sub-pr-120
Mossbraker Mar 19, 2026
012ea74
Merge pull request #121 from xxmjskxx/copilot/sub-pr-120
Mossbraker Mar 19, 2026
42062d8
Fix typo in Readme
Mossbraker Mar 19, 2026
3cdb512
Fix typo in README.md regarding issue creation
Mossbraker Mar 19, 2026
3a87fc3
Initial plan
Copilot Mar 19, 2026
5c5d7b7
style: annotate validator link helper input
Copilot Mar 19, 2026
07957db
Merge pull request #122 from xxmjskxx/copilot/sub-pr-120
Mossbraker Mar 19, 2026
b662af3
fix: comment out unused quantization formats in capture.py
Mossbraker Mar 19, 2026
5d55b86
Merge branch 'PR-fixes' of https://github.com/xxmjskxx/ComfyUI_SaveIm…
Mossbraker Mar 19, 2026
687914b
feat: add tests for metadata validation and workflow assignment logic
Mossbraker Mar 19, 2026
d705fcf
feat: enhance text input resolution in WorkflowAnalyzer and add scori…
Mossbraker Mar 19, 2026
5c30379
Merge pull request #120 from xxmjskxx/PR-fixes
Mossbraker Mar 19, 2026
fe70c24
Tighten metadata validation and runtime coverage
Mossbraker Mar 19, 2026
7d4ae78
Merge branch 'master' into validation-rx-fixes
Mossbraker Mar 19, 2026
277b8ab
Merge pull request #123 from xxmjskxx/validation-rx-fixes
Mossbraker Mar 19, 2026
82ef96f
chore: update readme for v1.4.2 release with prompt-routing and metad…
Mossbraker Mar 19, 2026
39130cb
v1.4.2 release notes
Mossbraker Mar 19, 2026
681d1cf
bump version to 1.4.2 in pyproject.toml
Mossbraker Mar 19, 2026
5ea2907
chore: update CHANGELOG for v1.4.2 release with highlights, additions…
Mossbraker Mar 19, 2026
880566b
chore: update .gitignore to include specific release notes and exclud…
Mossbraker Mar 19, 2026
50ebedd
Merge pull request #124 from xxmjskxx/pre-142-release
Mossbraker Mar 19, 2026
ff5275c
Initial plan
Copilot Mar 22, 2026
94c9bd3
Stop replacing commas with slashes in extra metadata values
Copilot Mar 22, 2026
bc23276
Merge pull request #126 from xxmjskxx/copilot/fix-concat-conditioning…
Mossbraker Mar 22, 2026
dccf058
Initial plan
Copilot Mar 22, 2026
0b0d7ee
fix: add lora_name to text field candidates and scalar fallback for L…
Copilot Mar 22, 2026
982882f
fix: respect active-field skip for lora_name fallback and unwrap wrap…
Copilot Mar 22, 2026
8630067
Merge pull request #128 from xxmjskxx/copilot/fix-lora-manager-hash-c…
Mossbraker Mar 22, 2026
a0a7adf
feat: add LoraManager compatibility helpers and tests for settings in…
Mossbraker Mar 23, 2026
2105a06
Update tests/test_lora_manager_compat.py
Mossbraker Mar 23, 2026
2f978f5
Initial plan
Copilot Mar 23, 2026
4c58aa9
Fix review feedback: update docstring, remove unused variable, fix cr…
Copilot Mar 23, 2026
01c0c45
Merge pull request #130 from xxmjskxx/copilot/sub-pr-129
Mossbraker Mar 23, 2026
7013dc5
fix: address PR #129 review comments on lora.py and test lint
Mossbraker Mar 23, 2026
054c696
fix: improve error handling for LoraManager user config path resoluti…
Mossbraker Mar 23, 2026
59832de
fix: address PR #129 review comments — error handling and test reliab…
Mossbraker Mar 23, 2026
0f791bd
Merge pull request #129 from xxmjskxx/dev/copilot/fix-lora-manager-ha…
Mossbraker Mar 24, 2026
4fc3739
feat: extend LoraManager extra-path support to checkpoints, UNets, an…
Mossbraker Mar 24, 2026
d28806a
fix: update .gitignore to include Claude directory
Mossbraker Mar 24, 2026
95e1bfe
Fix tuple handling, redundant call, and unbounded cache
EnragedAntelope Apr 21, 2026
05958fc
fix: resolve LoraManager path normalization and basename fallback
Mossbraker Apr 21, 2026
cefdae2
docs: clarify checkpoint and UNet dump flags
Copilot Apr 21, 2026
8cbcea2
docs: clarify dump path trimming behavior
Copilot Apr 21, 2026
ea17717
fix: simplify basename-only index resolvers
Mossbraker Apr 21, 2026
acd024a
test: replace resolver lambdas with local stubs
Copilot Apr 21, 2026
6853943
Merge pull request #134 from xxmjskxx/dev/feat/lora-manager-extra-pat…
Mossbraker Apr 22, 2026
00215db
reorder imports
Mossbraker Apr 22, 2026
2afebf6
docs: list checkpoint and UNet dump flags
Copilot Apr 22, 2026
a4ad975
docs: align dump flag wording
Copilot Apr 22, 2026
92d20b5
Fix uppercase extension indexing for LoRA manager compatibility
Mossbraker Apr 22, 2026
9c7fd47
fix: skip LoraManager embedding dirs in test mode
Mossbraker Apr 22, 2026
0d89228
fix(lora-manager): gate index resolvers on extra dirs and harden walks
Mossbraker Apr 22, 2026
a5635f7
fix(lora-index): normalize extension case in build_lora_index
Mossbraker Apr 22, 2026
909458c
docs(lora-manager): correct multi-type extra-paths wording; gate ckpt…
Mossbraker Apr 22, 2026
25a9aca
fix(lora-manager): rename test-gate helper, harden dump-path handling…
Mossbraker Apr 22, 2026
2c3666d
test(embedding): split traversal-guard test, add real multi-dir conti…
Mossbraker Apr 22, 2026
425c2d8
Merge branch 'master' into feat/lora-manager-extra-paths-all-model-types
Mossbraker Apr 23, 2026
066e26d
Merge pull request #133 from xxmjskxx/feat/lora-manager-extra-paths-a…
Mossbraker Apr 23, 2026
dfba9d4
Merge branch 'EnragedAntelopepr/bugfixes-and-improvements' into pr/bu…
Mossbraker Apr 23, 2026
f75413d
Merge pull request #132 from EnragedAntelope/pr/bugfixes-and-improvem…
Mossbraker Apr 23, 2026
66ec1cc
fix(pr-135): address Copilot review on bugfix PR
Mossbraker Apr 23, 2026
e7bbc18
docs(validators): document why is_node_connected keeps prompt strong-ref
Mossbraker Apr 23, 2026
fb5c3d2
test(efficiency): add tuple-specific advanced-mode coverage
Mossbraker Apr 23, 2026
7483998
Merge pull request #135 from xxmjskxx/EnragedAntelopepr/bugfixes-and-…
Mossbraker Apr 23, 2026
5396c5f
fix: enhance tooltip for filename prefix to include subdirectory supp…
Mossbraker Apr 23, 2026
9551816
Merge branch 'master' into bug/fix-filename-prefix-tooltip
Mossbraker Apr 23, 2026
02944ef
Merge pull request #136 from xxmjskxx/bug/fix-filename-prefix-tooltip
Mossbraker Apr 23, 2026
03f8b18
feat: enhance CreateExtraMetaDataUniversal to support dynamic key-val…
Mossbraker Apr 23, 2026
805158e
test: add tests for INPUT_TYPES and runtime pair handling in CreateEx…
Mossbraker Apr 23, 2026
05b49b4
Updated `unimeta-ci.yml:77` so the lint-autofix job checks out the pu…
Mossbraker Apr 23, 2026
60bb138
Address PR review feedback on issue 63: update extra metadata handlin…
Mossbraker Apr 24, 2026
5ce55b5
PR review follow-up: cleanup type hints and comments in extra_metadat…
Mossbraker Apr 24, 2026
062f787
Merge pull request #137 from xxmjskxx/fix-issue-63
Mossbraker Apr 24, 2026
abeb26e
feat: add advanced toggle for suppressing missing class log and model…
Mossbraker Apr 24, 2026
2c88538
Merge pull request #138 from xxmjskxx/save-image-advanced-toggle-debug
Mossbraker Apr 24, 2026
29d3a07
chore: bump version to 1.4.3 and update changelog/release notes
Mossbraker Jul 21, 2026
38bff00
docs: update README with v1.4.2 release notes
Mossbraker Jul 21, 2026
5d104ed
Merge pull request #143 from xxmjskxx/release/v1.4.3
Mossbraker Jul 21, 2026
aaebee0
fix: skip V3 subgraph dict links in graph tracers
EnragedAntelope Aug 23, 2026
a62151b
Use _is_link_input to validate input fields
Mossbraker Sep 4, 2026
7933c0f
Rename test for handling list-of-dicts inputs
Mossbraker Sep 4, 2026
a0e95e5
Modify test to skip list-of-dicts in BFS traversal
Mossbraker Sep 4, 2026
cea161f
Merge pull request #145 from EnragedAntelope/fix/v3-subgraph-dict-lin…
Mossbraker Sep 4, 2026
3b2695e
chore: bump version to 1.4.4 and update changelog/release notes
Mossbraker Sep 4, 2026
07c722d
docs: record full test suite count in v1.4.4 release notes
Mossbraker Sep 4, 2026
ce94908
Merge pull request #146 from xxmjskxx/release/v1.4.4
Mossbraker Sep 4, 2026
fe2b213
chore: carry local .gitignore updates
Mossbraker Sep 4, 2026
c10cf08
feat: redact secrets and sanitize output filenames in save node
Mossbraker Sep 4, 2026
e3773a3
Address review feedback on redaction + path safety
Mossbraker Sep 4, 2026
561d811
docs: drop markdown line-length rule and unwrap hard-wrapped prose
Mossbraker Sep 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[run]
branch = True
# Point to the actual package directory (relative to repo root)
source = saveimage_unimeta
omit =
*/tests/*
*/__init__.py
saveimage_unimeta/defs/ext/generated_user_rules.py

[report]
show_missing = True
skip_covered = True
fail_under = 35
exclude_lines =
pragma: no cover
if __name__ == .__main__.
66 changes: 66 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# AI Assistant Project Instructions
Authoritative onboarding for `ComfyUI_SaveImageWithMetaDataUniversal`. This repo is a Python custom-node pack (~220 tracked files excluding local-only `.venv`/outputs) targeting the ComfyUI runtime; edits usually run inside ComfyUI but must stay testable via pure Python.

## Overview & Tech Stack
- Purpose: `saveimage_unimeta/nodes/save_image.py` saves images with rich Automatic1111/Civitai-compatible metadata, hashes, workflow JSON, and filename tokens while degrading gracefully on JPEG limits.
- Languages & tooling: Python 3.10+ (CI runs 3.10–3.13), Pillow/Numpy/Piexif, ComfyUI APIs (`folder_paths`, `nodes`, `execution`). Browser assets under `web/` use HTML/JavaScript for optional UI helpers. Linting via Ruff (`ruff.toml`), testing via Pytest (`tests/`), coverage tracked by `.coveragerc`.
- Dependencies live in `requirements.txt` (runtime) and `requirements-test.txt` (adds pytest, ruff, coverage). Installing editable dev extras: `pip install -e .[dev]` (see `pyproject.toml`).

## Repository Layout (edit here before searching)
- Root: `saveimage_unimeta/` (core package), `tests/` (unit suites hitting public APIs), `docs/` (JPEG fallback, workflow compression, futures), `example_workflows/`, `user_rules/` (shipped examples), `.github/workflows/*.yml` (CI/publish), `web/` (static JS/CSS helpers referenced by ComfyUI UI), `ruff.toml`, `.pre-commit-config.yaml`.
- `saveimage_unimeta/defs/`: canonical capture metadata definitions, sampler heuristics, combo helpers, plus `ext/` for shipped extensions. Never bypass these when adding fields.
- `saveimage_unimeta/defs/validators.py`: prompt validators trace upstream from sampler inputs. Standard dual-path conditioning nodes and guiders are routed generically by matching positive/negative-style input names; keep explicit overrides in `defs/samplers.py` only for non-standard guider input names.
- `saveimage_unimeta/nodes/`: save node + supporting UI tooling (scanner, rule writers, extra metadata nodes, test stubs). Each node must keep tooltip text ≤140 chars (see `pyproject` metadata for copy text).
- `saveimage_unimeta/capture.py`: merges defs + `user_rules` + `FORCED_INCLUDE_CLASSES`, normalizes prompts, ensures `Metadata generator version` is always last. Relies on `saveimage_unimeta/hook.py` to read the active ComfyUI prompt cache (tests shim this when `METADATA_TEST_MODE=1`).
- `saveimage_unimeta/trace.py`: BFS graph traversal + sampler selection heuristics (exact match in `defs/samplers.py`, else `MetaField.SAMPLER_NAME` or `{STEPS, CFG_SCALE}` hint). `Trace.filter_inputs_by_trace_tree` guarantees deterministic ordering upstream of capture.
- `saveimage_unimeta/utils/`: hashing primitives (`hash.py`), LoRA/embed utilities, logging helpers (`color.py`), workflow redaction (`redaction.py`, bounded secret/path sanitization), and filename safety (`pathsafety.py`). Always use these helpers—no ad-hoc hashing/log formatting, prefer `pathresolve` for filesystem work, and route metadata/redaction and filename sanitization through the shared helpers.
- `web/`: static TypeScript/JavaScript snippets for optional UI affordances (see `web/js/`); keep them aligned with node parameter expectations when changing UI-visible behavior.

## Data Flow & Runtime Contracts
1. `Trace.trace` builds a distance map from the save node back through executed nodes; `sampler_selection_method` (UI) controls farthest/nearest/explicit traversal.
2. `Capture.gen_pnginfo_dict` / `.gen_parameters_str` iterate that ordering, apply rule merges, sanitize prompts, and append deterministic fields (metadata generator version last).
3. `saveimage_unimeta/nodes/save_image.py` writes PNGInfo or EXIF/WebP metadata, attempts JPEG EXIF up to `max_jpeg_exif_kb` (≤64 KB enforced). `_last_fallback_stages` mirrors whichever fallback stage fired. Before embedding, the `sanitize_metadata` toggle (default on) passes `prompt`/`extra_pnginfo` through `utils/redaction.py` (fail-open: falls back to raw on `MetadataSanitizationError`), and the expanded filename template is always passed through `utils/pathsafety.py` (`sanitize_filename`).
4. JPEG fallback follows the multi-stage pipeline documented in `.github/instructions/python.instructions.md`; `_last_fallback_stages` mirrors whichever stage triggered so downstream tests can assert the markers.
5. Hashing: `saveimage_unimeta/defs/formatters.py` (via helpers in `saveimage_unimeta/utils/hash.py`) caches full SHA256 hashes in `.sha256` sidecars which are truncated to 10 chars when written to metadata; `METADATA_FORCE_REHASH=1` invalidates caches. Hash log verbosity is controlled via `METADATA_HASH_LOG_MODE` and `METADATA_HASH_LOG_PROPAGATE`.

## Runtime Integration & Environment Flags
- Runs embedded in ComfyUI; expect access to `folder_paths`, sampler nodes, and numerous other `comfy.` imports, and PIL. When unit testing, `saveimage_unimeta/piexif_alias.py` and `hook.py` provide safe stubs—only extend the stub surface actually required.
- Runtime feature flags (read at execution time, no restart needed) include: `METADATA_TEST_MODE`, `METADATA_NO_HASH_DETAIL`, `METADATA_NO_LORA_SUMMARY`, `METADATA_FORCE_REHASH`, `METADATA_HASH_LOG_MODE`, `METADATA_HASH_LOG_PROPAGATE`, `METADATA_DUMP_LORA_INDEX`, `METADATA_DUMP_CHECKPOINT_INDEX`, `METADATA_DUMP_UNET_INDEX`, `METADATA_ENABLE_TEST_NODES`, `METADATA_DEBUG_PROMPTS`. UI checkbox `include_lora_summary` overrides the env flag.
- JPEG/env documentation source of truth: `docs/JPEG_METADATA_FALLBACK.md`, `docs/WORKFLOW_COMPRESSION_DESIGN.md`, `docs/FUTURE_AND_PROTOTYPES.md`. Update both docs + this file when behavior changes.

## Build, Lint, Test (validated locally and mirrored by CI)
1. **Bootstrap** (from repo root, Python ≥3.10):
```cmd
python -m venv .venv
.venv\Scripts\activate
python -m pip install --upgrade pip
pip install -e .[dev]
```
(Alternatively, `pip install -r requirements.txt -r requirements-test.txt`.)
2. **Lint**: `ruff check .` (configured by `ruff.toml`; CI fails on lint). Optional: `pre-commit run --all-files` (hooks defined in `.pre-commit-config.yaml`).
3. **Unit tests**: `pytest -q` (Pytest auto-discovers under `tests/`). Set `METADATA_TEST_MODE=1` to match CI matrix determinism. Coverage is gathered in CI via `coverage run -m pytest -q`; run locally when touching core pipeline.
4. **Workflow/CLI tests**: optional but recommended before shipping metadata format changes. Use `python tests/tools/run_dev_workflows.py --comfyui-path "<your ComfyUI root>" [--workflow-dir ...]` (see `tests/comfyui_cli_tests/DEV_WORKFLOW_TESTING.md` + `ignore/DEV_WORKFLOW_TESTING.md`). Always ensure workflows are in API format and clean outputs with `--temp-dir` or manual deletion.
5. **Integration sanity**: when touching JPEG fallback, temporarily set `max_jpeg_exif_kb=8` via the node UI or JSON to coerce fallback coverage; inspect `_last_fallback_stages` and resulting metadata strings to confirm markers append exactly once.
6. **CI awareness**: `.github/workflows/unimeta-ci.yml` is the primary matrix workflow (Ruff + Pytest across Python 3.10–3.13 with both metadata modes, plus lint-only jobs). `.github/workflows/ci.yml` remains from the old template and still targets the `main` branch—confirm no external automation depends on it before deleting or updating the triggers. `publish_action.yml` handles release packaging. Match local tooling to avoid failures.

## Rules, Scanner & User Overrides
- `saveimage_unimeta/nodes/scanner.py` inspects installed node classes and suggests capture rules. `rules_save.py` + `rules_view.py` manage JSON/Python persistence by writing the JSON blobs under `saveimage_unimeta/user_rules/`. `saveimage_unimeta/nodes/rules_writer.py` consumes those JSON files to regenerate `saveimage_unimeta/defs/ext/generated_user_rules.py`. After editing `defs/captures.py`, re-run scanner + saver so automated tests (`tests/test_generated_user_rules.py`) stay in sync. When users trigger node-driven backups, the `saveimage_unimeta/user_rules/backups/` folder may contain timestamped copies of the JSON files and the generated module.
- `rules_writer.py` stamps a `RULES_VERSION` constant into generated modules; `defs.load_user_definitions` caches it as `LOADED_RULES_VERSION`. `save_image.py` logs a one-time warning when the saved rules are missing or outdated—ask users to re-run `Metadata Rule Scanner` + `Save Custom Metadata Rules` or execute `example_workflows/refresh-rules.json` after updates.
- `Metadata Force Include` node feeds `FORCED_INCLUDE_CLASSES` used during capture merge; keep manual overrides inside `saveimage_unimeta/user_rules/` so merges remain deterministic.
- Manual capture additions must update: `defs/captures.py`, `_build_minimal_parameters` (only if the field must survive minimal fallback), docs (README + `docs/...`), targeted tests (e.g., `tests/test_capture_core.py`, `tests/test_guidance_and_exif_fallback.py`).

## Conventions & Safety Nets
- `.github/instructions/python.instructions.md` is the authoritative source for coding conventions, logging patterns, runtime import guards, metadata ordering, JPEG fallback behavior, filename token safety, helper usage, UI override precedence, sanitization rules, and artifact locations. Follow it whenever editing `.py` files.
- `.github/instructions/comfy.instructions.md` documents the ComfyUI manifest contract (`__init__.py` exports, `NODE_CLASS_MAPPINGS`, `NODE_DISPLAY_NAME_MAPPINGS`) and protocol expectations (`CATEGORY`, `RETURN_TYPES`, `INPUT_TYPES`, `FUNCTION`, tuple returns). Reference it when adding or modifying nodes.

## Integration Resources & Troubleshooting
- **Docs**: `docs/JPEG_METADATA_FALLBACK.md`, `docs/MIGRATIONS.md`, `docs/V3_SCHEMA_MIGRATION.md` (for future migration to V3; no specific timeline for implementing this yet), `docs/WAN22_SUPPORT.md`, `docs/FUTURE_AND_PROTOTYPES.md` (historical context). Keep them synchronized with behavior changes.
- **Workflow samples**: `example_workflows/*.json` showcase Force Include, extra metadata, LoRA stacks, WAN/FLUX flows. Use them to reproduce bugs quickly.
- **Testing aids**: `saveimage_unimeta/nodes/testing_stubs.py` exposes lightweight sampler nodes when `METADATA_ENABLE_TEST_NODES=1`; `tests/` contains stub fixtures demonstrating how to patch ComfyUI APIs.
- **Troubleshooting tips**: enable `METADATA_DEBUG_PROMPTS=1` to log prompt aliasing, drop `max_jpeg_exif_kb` to 8 to hit fallback paths, set `METADATA_NO_HASH_DETAIL=1` or `METADATA_NO_LORA_SUMMARY=1` to verify UI overrides, and use `METADATA_DUMP_LORA_INDEX`, `METADATA_DUMP_CHECKPOINT_INDEX`, or `METADATA_DUMP_UNET_INDEX` to dump the first-built indexes for diagnostics. Hash mismatches? delete `.sha256` sidecars or set `METADATA_FORCE_REHASH=1`.

## Working Style & Search Discipline
- Start from this file: it summarizes architecture, commands, and directory hotspots—search the codebase only if something here is missing or inaccurate. When in doubt, inspect `saveimage_unimeta/` modules referenced above before global greps.
- Keep diffs surgical: modify only the modules relevant to your change, maintain doc parity (README + docs + this file), and update/extend tests covering the touched behavior. CI enforces Ruff + Pytest; aim to replicate locally before pushing.
- Document new env flags, workflow parameters, or fallback behaviors immediately here and in the README/doc section they affect. Avoid conflicting guidance—the coding agent will obey the strictest rule present.
- Trust these instructions. Only run exploratory searches if the required information isn’t covered or appears outdated, and if you discover drift, update this file as part of your change.
89 changes: 89 additions & 0 deletions .github/instructions/comfy.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
---
description: "ComfyUI protocol guarantees and manifest/registration contract."
applyTo: "**/*.py"
---

# GitHub Copilot Instructions for `ComfyUI_SaveImageWithMetaDataUniversal`

## How This File Fits With Other Instructions

- Use `.github/copilot-instructions.md` for the full repo tour (layout, data flow, build/test commands, env flags).
- Use `.github/instructions/python.instructions.md` for every Python-convention question (ruff expectations, logging, metadata ordering, JPEG fallback, helper usage). That file is the authority on code style and testing rules.
- This document focuses solely on **ComfyUI protocol guarantees** and the **manifest/registration contract** that every node must respect.

## Architecture Layers (ComfyUI View)

1. **Registration Layer (`__init__.py`)** – Treat this as the manifest. It should primarily import concrete node classes, declare `NODE_CLASS_MAPPINGS`, `NODE_DISPLAY_NAME_MAPPINGS`, optional `WEB_DIRECTORY`, and export the curated `__all__`. Controlled side effects (e.g., gating test nodes on `METADATA_ENABLE_TEST_NODES` or logging a one-time startup banner) are acceptable, but keep them lightweight and well-documented.
2. **Logic Layer (`saveimage_unimeta/`)** – All node behavior, utilities, capture/trace helpers, and metadata plumbing live inside this package. New functionality must be implemented here and tested via `pytest` as described in the Python instructions.
3. **Presentation Layer (`web/`)** – Houses any optional ComfyUI frontend extensions. Keep the JS aligned with node INPUT_TYPES and update the manifest’s `WEB_DIRECTORY` when shipping UI assets.

## ComfyUI Protocol Requirements

When writing or modifying nodes, enforce these protocol rules to stay compatible with ComfyUI and downstream forks:

- Define the static protocol fields on every node class: `CATEGORY`, `RETURN_TYPES`, `FUNCTION`, and, when applicable, `OUTPUT_NODE` or `OUTPUT_IS_LIST`.
- Implement `@classmethod INPUT_TYPES(cls)` returning a dict with `"required"`, `"optional"`, and `"hidden"` keys. Ensure magic strings (e.g., `"IMAGE"`, `"STRING"`, `"UNIMETA_METADATA"`) match the runtime’s expectations.
- The method referenced by `FUNCTION` must accept parameters that line up exactly with `INPUT_TYPES` and always return a tuple. Saver nodes typically `return ()` to signal “work complete, no tensors produced.”
- Hidden inputs for prompt/workflow/state (`"PROMPT"`, `"EXTRA_PNGINFO"`, etc.) must be threaded through to capture utilities rather than reinventing workflow parsing.

## Registration Checklist

Whenever a new node class is introduced under `saveimage_unimeta/nodes/`:

1. Import the class inside the root `__init__.py` without triggering runtime-only dependencies during import.
2. Add the class to `NODE_CLASS_MAPPINGS` using the ComfyUI identifier as the key.
3. Provide a concise (<140 char) entry in `NODE_DISPLAY_NAME_MAPPINGS` so UI menus look polished.
4. Append the class name to `__all__` to keep static analyzers in sync.
5. If the node requires web assets, expose them via `WEB_DIRECTORY` and keep the folder paths stable for ComfyUI.

## Gold-Standard Node Outline

New nodes should resemble the structure below. It highlights the ComfyUI-specific plumbing this document governs; read the Python instructions for broader style and metadata rules.

```python
import torch
from comfy.cli_args import args


class SaveImageWithMetaDataUniversal:
"""Canonical saver node registered via NODE_CLASS_MAPPINGS."""

CATEGORY = "image/metadata"
RETURN_TYPES: tuple[str, ...] = ()
FUNCTION = "save_images"

@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE",),
"filename_prefix": ("STRING", {"default": "ComfyUI"}),
},
"optional": {
"extra_metadata": ("UNIMETA_METADATA",),
"metadata_rules": ("UNIMETA_RULES",),
},
"hidden": {
"prompt": "PROMPT",
"extra_pnginfo": "EXTRA_PNGINFO",
},
}

def save_images(
self,
images: torch.Tensor,
filename_prefix: str,
extra_metadata: dict | None = None,
metadata_rules: dict | None = None,
prompt: dict | None = None,
extra_pnginfo: dict | None = None,
) -> tuple:
if args.dont_save_previews:
return ()

# Business logic defined in saveimage_unimeta/nodes/save_image.py

return ()
```

Use this outline to validate that protocol attributes, INPUT_TYPES, and return signatures remain aligned whenever you extend the saver or add supporting nodes.
Loading