Files
ausboss-ComfyUI-AusBoss/js/shared/graph_ids.mjs
T
ausboss 895493c49c Mask by Name: the card, the FIND button and the picture on the node
Registers the node, gives it a widget card and the shared preview panel
with a FIND tool that runs the node alone, a readout of how many things
matched and how sure SAM 3 was, and the stop message on the node's own
face. A stopped run shows the plain picture, not the last find. Each name
asks SAM 3 for up to 16 matches, and Sureness starts at 0.7.
2026-10-06 09:59:28 -05:00

49 lines
2.1 KiB
JavaScript

// Resolving ComfyUI execution ids to graph nodes.
//
// Kept free of /scripts/app.js imports so node:test can cover it
// (tests/graph_ids.test.mjs); callers pass the root graph in.
// ComfyUI identifies a node inside a subgraph by its execution id: the chain
// of subgraph node ids that reaches it, colon-joined ("12:3" is node 3 inside
// the subgraph node 12 holds). Only the last segment is a real graph node id,
// and ids are numbered independently inside each subgraph, so looking the
// bare tail up on the root graph does not merely miss - it can return a
// completely unrelated top-level node that happens to share the number.
// Walking the chain is the only way to answer correctly; an id that does not
// resolve returns null, because acting on the wrong node is worse than doing
// nothing at all.
export function nodeByExecutionId(rootGraph, executionId) {
const parts = String(executionId ?? "")
.split(":")
.filter((part) => part !== "");
if (!parts.length) return null;
let graph = rootGraph ?? null;
for (const part of parts.slice(0, -1)) {
const holder = graph?.getNodeById?.(Number(part)) ?? graph?.getNodeById?.(part);
graph = holder?.subgraph ?? null;
if (!graph) return null;
}
const tail = parts[parts.length - 1];
return graph?.getNodeById?.(Number(tail)) ?? graph?.getNodeById?.(tail) ?? null;
}
// The other way round: a node's execution id, found by walking from the root
// graph down through the boxes (subgraph nodes) that hold it. This is what a
// run of one node alone has to name. A box that is used twice gives its first
// use; a node that is on no graph gives null.
export function executionIdOf(rootGraph, node) {
if (!rootGraph || !node) return null;
const walk = (graph, prefix, depth) => {
const nodes = graph?.nodes ?? graph?._nodes ?? [];
if (nodes.includes(node)) return `${prefix}${node.id}`;
if (depth > 16) return null;
for (const holder of nodes) {
if (!holder?.subgraph) continue;
const found = walk(holder.subgraph, `${prefix}${holder.id}:`, depth + 1);
if (found) return found;
}
return null;
};
return walk(rootGraph, "", 0);
}