Pipeline wiring: core/graph.py gains wire()/unwire(), and the "Models and
pipeline" editor can now actually connect one node's output to another's
input -- sockets and widgets alike, which is what makes "linked inputs"
(several widgets sharing one Primitive node's value) buildable at all,
without a second mechanism. Three adversarial review rounds found and fixed
real bugs along the way: check()'s request builder silently dropped the
wire-specific fields; the widgets loop had no wiring UI at all despite the
backend supporting it, and a widget already holding a link rendered as an
editable box with the wrong (default) value; wiring an input that already
had an unsaved drafted value let the stale value silently win on Save. Also
fixed, found live rather than by review: the Add-node picker stacked two
disagreeing search boxes (an outer server search and filterList's own
redundant client-side one).
Updates window: "Restart ComfyUI" is now a plain, always-available button,
not just something offered when an update already landed. Rolling back or
switching branch on a dirty tree now auto-stashes instead of refusing --
updating still refuses, unchanged, since pulling new commits onto changes
in progress is not something to do without asking. Three review rounds
here too: stashing before reading the rollback target shifted what HEAD@{1}
meant (a real reflog hazard, not just reasoned about); a stash's disclosure
was lost if the step right after it failed; that fix was too narrow and
missed pull()'s own failures inside checkout(pull_after=True) -- the actual
default path -- and rollback()'s own reset failing; and finally, the
broadened fix still only caught GitUpdateError, missing subprocess-level
failures like a hung fetch timing out, which is the realistic failure mode
on a rented GPU box's network.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ComfyUI spells a combo three ways -- a list where the type goes, the string
"COMBO" with the choices under options, and COMFY_DYNAMICCOMBO_V3. Only the
first was read, so every V3 node came back with no choices at all and the
window said "no files of this kind were found" over dropdowns holding seven
entries. A stock install here has 140 of the spelling that was missed.
A union type ("IMAGE,MASK") was compared as a whole string, so a MASK feeding
it was refused -- a legal wire refused, which is as bad as an illegal one
accepted. A MultiType wrapped around a number ("FLOAT,INT" with widgetType)
was read as a socket demanding a source for a field you type into.
graph.py and widgets.py had their own idea of what a type string means; both
now read comfy_types.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
graph.py reads an input's TYPE, which is all a wire needs. Editing a value needs
the rest -- the choices a combo offers, the bounds on a number, whether the box
is multiline -- so that is asked separately rather than widening the question
graph.py asks. Read from ComfyUI's own INPUT_TYPES, so a node written for
ComfyUI is editable here without knowing anything about FunPack.
Caught while looking at the real output rather than after committing: deciding
"a socket is upper case" is wrong, because STRING is upper case -- every prompt
box in the pipeline came back as something nobody could type in. The honest rule
is ComfyUI's own primitive set, plus forceInput, which is a short list core
holds on purpose.
/funpack/api/nodes answers by name. ComfyUI's /object_info returns every
installed node, which on a machine with a few packs is megabytes for a question
about a dozen; a node nobody installed comes back as null rather than missing,
so "this slot points at something absent" reads differently from "I did not ask".
The dev server now registers ComfyUI's nodes and FunPack's own, through the same
function the tests use. Without it the pipeline was fourteen "there is no node
called X installed" and nothing to edit -- so the one thing the dev server exists
for could not reach the half of the app that matters. It now reports the three
problems that are real: no model, no CLIP, no VAE chosen.