With server tokens attached automatically, an http:// Civitai or Hugging
Face link in a shared workflow would have sent the token in cleartext.
Both downloaders now fetch those links over https, and redirects drop
the Authorization header on any hop that is not https.
A token typed on the node is saved inside the workflow, so sharing a
workflow shared the token. Civitai and Hugging Face now use the server's
token when api_token is empty: CIVITAI_API_KEY (or CIVITAI_API_TOKEN,
CIVITAI_TOKEN) and HF_TOKEN (or HUGGING_FACE_HUB_TOKEN, or the token
`hf auth login` saved). Each token goes only to its own site; custom URLs
only ever get a typed token.
Civitai now serves models on civitai.green and civitai.red as well as
civitai.com. Links from all three are detected, and downloads go through
civitai.com. A Civitai download with a filename that already exists
returns before any API call, so a workflow can keep its downloaders and
stay offline once the files are there.
The test host unpacked two values from load_media, and the gallery
test expected no stored selection although the gallery now stores the
folder it shows. Return and assert the folder instead.
The Local Image Loader can browse folders visually, but only output a
picked image. Add a third output, folder: the path of the folder the
gallery shows, or the picked image's folder until the user browses.
Browsing is enough, so a training dataset can be found by its thumbnails
and passed to a node that reads a whole folder.
The gallery stores the shown folder through set_node_selection (type
"folder"), which accepts only directories inside the allowed roots;
load_media checks the stored folder against the roots again.
- The Nodes 2.0 context menu converts litegraph items itself and only
renders submenu.options for entries flagged has_submenu, so the
"Custom Colors" entry was an inert label there; litegraph's own menu
accepts either flag, so set both
- Add a real-host test that drives the actual right-click menu in both
renderers through to the color dialog; the existing test invoked the
callbacks directly and bypassed the converter
- Assert has_submenu on the node and group entries in the browser suite
- Collapse the console banner to a single line with the version and the
tool count instead of one `Loaded:` line per node, matching
ComfyUI-PromptManager
- Keep the banner ASCII so a legacy Windows console cannot abort the load
- Update the console encoding test to assert the summary line
- Ship the Krea 2 resolution family already on main
- Bump pyproject.toml to 1.3.1 and date the changelog section
Krea 2 uses the Wan 2.1 latent (8x VAE) with patch 2, so sizes sit on a
16 px grid. Tiers 1.0 / 2.0 / 4.0 MP cover the model card's 1024x1024 and
2048x2048; Big Love KreaEdit3's 1024x1536 is listed under 2:3.
- PR #108 changed pyproject.toml without bumping the version, so the
registry publish on main failed with "The node version already exists".
- Bump to 1.3.0 (new node, route and override file) and add the release
notes to CHANGELOG.md and the README.
- An override family could declare a step such as 3; sizes rounded to it
are not divisible by 8, so create_empty_latent_batch raised ValueError
at execution instead of producing a latent (Codex review on PR #108).
- validate_table now rejects a step that is not a multiple of 8 with a
message naming the latent grid; the shipped steps (16, 32, 64) already
comply, and the schema docs state the rule.
- The ResizeObserver callback measured the panel and resized the node
synchronously, which forces a layout while the stylesheet may still be
applying; WebKit then reports "ResizeObserver loop completed with
undelivered notifications" as a page error, and the browser fixture
fails any test with a page error (CI WebKit job on PR #108).
- The callback now only schedules a single-flight requestAnimationFrame
that measures and refits, so no observed box changes during delivery.
- Reproduced in the pinned Playwright WebKit image: the picker tests pass
48/48 (16 tests × 3) with this change.
- New nodes started at a fixed 340×600, so one-entry size lists left a
large empty area between the list and the Swap button.
- The panel now reports its measured content height as both the minimum
and maximum DOM-widget height, and the extension sets the node height to
the host's computeSize() after every render, keeping the width.
- Hidden or detached panels are not measured, the first measurement is
retried for a few frames, and a ResizeObserver on the panel children
refits when the stylesheet arrives after the first render (the coverage
run exposed that race; a held-stylesheet regression test pins it).
- Workflows load at their saved width and are re-fitted on load; the spec
and docs describe the new sizing rule.
- edits show up on a page reload or Refresh node definitions, not on the
next node mount, because the frontend caches the payload per page
- the 14 count refers to shipped families; an override can add or remove
- workflows saved before the resolution widget load shifted by one slot
- onConfigure now maps exactly four widgets_values onto model, width,
height and batch_size and resets resolution to custom
- the host test stub applies widgets_values and calls onConfigure like LiteGraph
- table validation accepts sides 64..8192, matching the widget min/max
- parse_size_label (Python and JS) caps digits and rejects out-of-range
sizes so create() falls back to width/height instead of overflowing
- family_labels() and the combo default now read the merged table, so an
appended family is selectable and a removed one is not offered
- an alias used as the override default is normalised to its label
- the frontend rebuilds the model options from the payload and keeps a
saved family that is no longer listed so old workflows still show it
- replace the {ex} placeholder with a real override example validated against validate_table
- list the loading state among the cases that show custom
- say the override default may be a label or alias
- describe the families.json schema and the user override file with a full example
- document the warnings behaviour and resolution dropdown precedence
- add the dropdown sync rule to web/ui/README.md
- Set resolution to custom whenever the panel has no selection (wired,
failed, non-finite or loading) so a stale label cannot override width/height.
- Compute label megapixels with 1 MP = 1,048,576 px, matching the panel
header, with half-up rounding so Python and JS labels agree on ties.
- Add a native resolution COMBO (shipped sizes only) so a size can be picked
and saved in the workflow without the panel; custom or unparseable labels
fall back to width/height on both sides.
- Mirror the dropdown with the chips: options follow the active chip, the
value tracks the current size, and picking a label writes width/height.
- Draw a decorative ratio shape on each ratio chip and show the first
families warning in the status line.
- catch RecursionError alongside ValueError when loading, merging and validating
- add tests for deep nesting, remove vs families, and a default naming a removed family
- add override.py: override_path, merge_override, mtime-cached current_table
- resolve_family and families_payload consult the merged table and expose warnings
- an invalid override is ignored whole with a logged warning
- treat ints as finite instead of calling math.isfinite on them
- bound step (4096), megapixels (64) and side length (65536) with normal problem messages
- cover step, megapixels, default and size values of 10**400
- check default, labels and aliases are strings before set membership
- reject non-finite step and megapixels via a shared _is_step helper
- cover unhashable and Infinity/NaN inputs in the garbage test
- ship the table as families.json with per-family notes from the old source comments
- add table.py: load_table, pure validate_table and build_families
- families.py loads and validates at import, raising RuntimeError on problems
- include *.json as package data
- VALIDATE_INPUTS lets unknown family labels reach create()
- no size is listed under two chips; SD 1.5 3:4 gets true 3:4 sizes
- model change before the families payload loads is applied on load
- custom ratio: clear error on chip click, cap sides at 8192, accept X
- real-host assertions for model change and wired-in state
- name Flux.2 / Klein / MOSS at 1248x832 and HunyuanImage 2.1 at 2560x1536
- require saved PNG dimensions to match the node outputs, recorded in the PR
- add README tools row, section and status row
- add ui-migration row and web/ui README section
- add per-node doc with family table and manual GPU check
- extract the real-host beforeEach into tests/comfyui/host-setup.mjs and proxy /kikotools/model_resolution/ to the fixture
- add the picker spec: renderer switching, shared swap, themes, workflow reload, scope abort
- add light and dark screenshots for the docs
- render the static chip list in every state; payload only drives enabled/active
- re-derive size on model change via sizeOnModelChange
- validate custom ratio, keep last valid list, ignore repeated commits
- add swap, model change, custom ratio and route failure browser tests
- add coverage floors for the three picker files
- restore keyboard focus to the equivalent button after each render
- keep the accent background when hovering a pressed chip or size
- refresh the panel when input links change
- treat a size listed in the clicked chip as a no-op
- add resolution picker view with chip grid, size list and custom ratio input
- add extension that projects native widgets and writes sizes via callbacks
- add browser tests for rendering, theming, idempotent mount and disposal
- Treat a missing preset widget like preset value 'custom' in swapDimensions
- Keep every preset access behind the custom check
- Add a test that swaps width and height directly on a preset-less node
- add ModelResolutionPickerNode rounding to the family step
- serve GET /kikotools/model_resolution/families
- register the node in NODE_CLASS_MAPPINGS
- add CHIPS, MIRROR, Family and the FAMILIES literal table
- add family_labels, resolve_family and families_payload helpers
- cover step, ratio, mirror and sort invariants with tests