Add custom nodes, Civitai loras (LFS), and vast.ai setup script
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.10, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.11, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-stable (12.1, , linux, 3.12, [self-hosted Linux], stable) (push) Has been cancelled
Full Comfy CI Workflow Runs / test-unix-nightly (12.1, , linux, 3.11, [self-hosted Linux], nightly) (push) Has been cancelled
Execution Tests / test (macos-latest) (push) Has been cancelled
Execution Tests / test (ubuntu-latest) (push) Has been cancelled
Execution Tests / test (windows-latest) (push) Has been cancelled
Test server launches without errors / test (push) Has been cancelled
Unit Tests / test (macos-latest) (push) Has been cancelled
Unit Tests / test (ubuntu-latest) (push) Has been cancelled
Unit Tests / test (windows-2022) (push) Has been cancelled

Includes 30 custom nodes committed directly, 7 Civitai-exclusive
loras stored via Git LFS, and a setup script that installs all
dependencies and downloads HuggingFace-hosted models on vast.ai.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-09 00:55:26 +00:00
parent 2b70ab9ad0
commit f09734b0ee
2274 changed files with 748556 additions and 3 deletions

View File

@@ -0,0 +1,153 @@
/**
* These contain types from ComfyUI (or LiteGraph) that are either copied or manually determined
* added here mostly because @comfyorg/comfyui-frontend-types hasn't exported them oir they weren't
* available.
*/
import type {SerializedGraph} from './index.js';
export type getPngMetadata = (file: File | Blob) => { workflow?: string; prompt?: string };
export type getWebpMetadata = (file: File | Blob) => {
Workflow?: string;
workflow?: string;
Prompt?: string;
prompt?: string;
};
// Below are types derived from the Serialized version of a workflow.
// export type SerializedLink = [
// number, // this.id,
// number, // this.origin_id,
// number, // this.origin_slot,
// number, // this.target_id,
// number, // this.target_slot,
// string, // this.type
// ];
// interface SerializedNodeInput {
// name: string;
// type: string;
// link: number;
// }
// interface SerializedNodeOutput extends SerializedNodeInput {
// slot_index: number;
// links: number[];
// }
// export interface SerializedNode {
// // id: number;
// // inputs: SerializedNodeInput[];
// // outputs: SerializedNodeOutput[];
// mode: number;
// order: number;
// pos: [number, number];
// properties: any;
// size: [number, number];
// type: string;
// widgets_values: Array<number | string>;
// }
// export interface SerializedGraph {
// config: any;
// extra: any;
// groups: any;
// last_link_id: number;
// last_node_id: number;
// links: SerializedLink[];
// nodes: SerializedNode[];
// }
/**
* ComfyUI-Frontend defines a ComfyNodeDef from Zod, but doesn't expose it. This is a shim.
*/
export type ComfyNodeDef = {
name: string;
display_name?: string;
description?: string;
category: string;
input?: {
required?: Record<string, [string | any[]] | [string | any[], any]>;
optional?: Record<string, [string | any[]] | [string | any[], any]>;
hidden?: Record<string, [string | any[]] | [string | any[], any]>;
};
output?: string[];
output_name: string[];
// @rgthree
output_node?: boolean;
};
// Below are types derived from the formats for the ComfyAPI.
// @rgthree
type ComfyApiInputLink = [
/** The id string of the connected node. */
string,
/** The output index. */
number,
]
type ComfyApiFormatNode = {
"inputs": {
[input_name: string]: string|number|boolean|ComfyApiInputLink,
},
"class_type": string,
"_meta": {
"title": string,
}
}
export type ComfyApiFormat = {
[node_id: string]: ComfyApiFormatNode
}
export type ComfyApiPrompt = {
workflow: SerializedGraph,
output: ComfyApiFormat,
}
export type ComfyApiEventDetailStatus = {
exec_info: {
queue_remaining: number;
};
};
export type ComfyApiEventDetailExecutionStart = {
prompt_id: string;
};
export type ComfyApiEventDetailExecuting = null | string;
export type ComfyApiEventDetailProgress = {
node: string;
prompt_id: string;
max: number;
value: number;
};
export type ComfyApiEventDetailExecuted = {
node: string;
prompt_id: string;
output: any;
};
export type ComfyApiEventDetailCached = {
nodes: string[];
prompt_id: string;
};
export type ComfyApiEventDetailError = {
prompt_id: string;
exception_type: string;
exception_message: string;
node_id: string;
node_type: string;
node_id: string;
traceback: string;
executed: any[];
current_inputs: {[key: string]: (number[]|string[])};
current_outputs: {[key: string]: (number[]|string[])};
}

View File

@@ -0,0 +1,30 @@
/**
* Declare any global properties and import our other typings here.
*/
import "@comfyorg/frontend";
import "./litegraph";
import "./rgthree";
import "./comfy";
import type {
LGraphGroup as TLGraphGroup,
LGraphNode as TLGraphNode,
LGraph as TLGraph,
LGraphCanvas as TLGraphCanvas,
LiteGraph as TLiteGraph,
} from "@comfyorg/frontend";
declare global {
const LiteGraph: typeof TLiteGraph;
const LGraph: typeof TLGraph;
const LGraphNode: typeof TLGraphNode;
const LGraphCanvas: typeof TLGraphCanvas;
const LGraphGroup: typeof TLGraphGroup;
interface Window {
// Used in the common/comfyui_shim to determine if we're in the app or not.
comfyAPI: {
// So much more stuffed in here, add as needed.
[key: string]: any;
};
}
}

View File

@@ -0,0 +1,193 @@
/**
* This used to augment the LiteGraph types, either to fix them for how they actually behave
* (e.g. marking args that are typed as required as optional because they actually are, etc.) or
* adding properties/methods that rgthree-comfy adds/uses. Mostly the latter are prefixed 'rgthree_'
* but not always.
*/
import "@comfyorg/frontend";
declare module "@comfyorg/frontend" {
interface INodeSlot {
// @rgthree: Hides a slot for rgthree-comfy draw methods.
hidden?: boolean;
// @rgthree: Used to "disable" an input/output. Used in PowerPrompt to disallow connecting
// an output if there's no optional corresponding input (since, that would just break).
disabled?: boolean;
// @rgthree: A status we put on some nodes so we can draw things around it.
rgthree_status?: "WARN" | "ERROR";
}
interface LGraph {
// @rgthree (Fix): `result` arg is optional in impl.
findNodesByType(type: string, result?: LGraphNode[]): LGraphNode[];
}
interface LGraphNode {
// @rgthree: rgthree-comfy added this before comfyui did and it was a bit more flexible.
removeWidget(widget: IBaseWidget | IWidget | number | undefined): void;
// @rgthree (Fix): Implementation allows a falsy value to be returned and it will suppress the
// menu all together.
// NOTE: [🤮] We can't actually augment this because it's a return.. but keeping here because
// this is how it's actually implemented.
// getSlotMenuOptions?(this: LGraphNode, slot: IFoundSlot): IContextMenuValue[] | void;
// @rgthree (Fix): Implementation allows a falsy value to be returned and it will not add items.
// NOTE: [🤮] We can't actually augment this because it's a return.. but keeping here because
// this is how it's actually implemented.
// getExtraMenuOptions?(
// canvas: LGraphCanvas,
// options: (IContextMenuValue<unknown> | null)[],
// ): (IContextMenuValue<unknown> | null)[] | void;
/**
* Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts
*
* Callback invoked when the node is dragged over from an external source, i.e.
* a file or another HTML element.
* @param e The drag event
* @returns {boolean} True if the drag event should be handled by this node, false otherwise
*/
onDragOver?(e: DragEvent): boolean;
/**
* Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts
*
* Callback invoked when the node is dropped from an external source, i.e.
* a file or another HTML element.
* @param e The drag event
* @returns {boolean} True if the drag event should be handled by this node, false otherwise
*/
onDragDrop?(e: DragEvent): Promise<boolean> | boolean;
/** Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts */
onExecuted?(output: any): void;
/**
* Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts
*
* Index of the currently selected image on a multi-image node such as Preview Image
*/
imageIndex?: number | null;
/** Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts */
overIndex?: number | null;
/** Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts */
imgs?: HTMLImageElement[];
/** Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts */
refreshComboInNode?(defs: Record<string, ComfyNodeDef>);
/**
* Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts
*
* widgets_values is set to LGraphNode by `LGraphNode.configure`, but it is not
* used by litegraph internally. We should remove the dependency on it later.
*/
widgets_values?: unknown[];
}
/**
* Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts
*
* Only used by the Primitive node. Primitive node is using the widget property
* to store/access the widget config.
* We should remove this hacky solution once we have a proper solution.
*
* @rgthree - Changed this to add `widget?: IWidgetLocator` to INodeOutputSlot (which matches
* INodeInputSlot) and then `[key: symbol]: unknown` to IWidgetLocator as that's how it's
* used for CONFIG and GET_CONFIG symbols.
*/
interface INodeOutputSlot {
widget?: IWidgetLocator; //{name: string; [key: symbol]: unknown};
}
// @rgthree - See above.
interface IWidgetLocator {
[key: symbol]: unknown;
}
interface LGraphGroup {
// @rgthree: Track whether a group has any active node from the fast group mode changers.
rgthree_hasAnyActiveNode?: boolean;
}
interface LGraphCanvas {
// @rgthree (Fix): At one point this was in ComfyUI's app.js. I don't see it now... perhaps it's
// been removed? We were using it in rgthree-comfy.
selected_group_moving?: boolean;
// @rgthree (Fix): Allows LGraphGroup to be passed (it could be `{size: Point, pos: Point}`).
centerOnNode(node: LGraphNode | LGraphGroup);
// @rgthree (Fix): Makes item's fields optiona, and other params nullable, as well as adds
// LGraphGroup to the node, since the implementation accomodates all of these as typed below.
// NOTE: [🤮] We can't actually augment this because it's static.. but keeping here because
// this is how it's actually implemented.
// static onShowPropertyEditor(
// item: {
// property?: keyof LGraphNode | undefined;
// type?: string;
// },
// options: IContextMenuOptions<string> | null,
// e: MouseEvent | null,
// menu: ContextMenu<string> | null,
// node: LGraphNode | LGraphGroup,
// ): void;
}
interface LGraphNodeConstructor {
// @rgthree (Fix): Fixes ComfyUI-Frontend which marks this as required, even though elsewhere it
// defines it as optional (like for the actual for LGraphNode). Our virtual nodes do not have
// a comfyClass since there's nothing to tie it back to.
comfyClass?: string;
// @rgthree: reference the original nodeType data as sometimes extensions clobber it.
nodeType?: LGraphNodeConstructor | null;
}
}
declare module "@/lib/litegraph/src/types/widgets" {
interface IBaseWidget {
// @rgthree (Fix): Where is this in Comfy types?
inputEl?: HTMLInputElement;
// @rgthree: A status we put on some nodes so we can draw things around it.
rgthree_lastValue?: any;
/** Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts */
onRemove?(): void;
/** Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts */
serializeValue?(node: LGraphNode, index: number): Promise<unknown> | unknown;
}
interface IWidgetOptions {
/**
* Copied from https://github.com/Comfy-Org/ComfyUI_frontend/blob/ba355b543d0b753365c4e2b40ec376e186727c8c/src/types/litegraph-augmentation.d.ts
*
* Controls whether the widget's value is included in the API workflow/prompt.
* - If false, the value will be excluded from the API workflow but still serialized as part of the graph state
* - If true or undefined, the value will be included in both the API workflow and graph state *
* @default true
* @use {@link IBaseWidget.serialize} if you don't want the widget value to be included in both
* the API workflow and graph state.
*/
serialize?: boolean;
}
}
declare module "@/lib/litegraph/src/interfaces" {
// @rgthree (Fix): widget is (or was?) available when inputs were moved from a widget.
interface IFoundSlot {
widget?: IBaseWidget;
}
}
declare module "@comfyorg/litegraph/dist/LiteGraphGlobal" {
interface LiteGraphGlobal {
// @rgthree (Fix): Window is actually optional in the code.
closeAllContextMenus(ref_window?: Window): void;
}
}

View File

@@ -0,0 +1,75 @@
/**
* Typings specific to rgthree-comfy.
*/
import type { LGraphNode, Vector2 } from "@comfyorg/frontend";
import type { CanvasMouseEvent } from "@comfyorg/litegraph/dist/types/events.js";
import type { RgthreeBaseNode, RgthreeBaseVirtualNode } from '../comfyui/base_node.js'
export type AdjustedMouseCustomEvent = CustomEvent<{ originalEvent: CanvasMouseEvent }>;
export type Constructor<T> = new(...args: any[]) => T;
export interface RgthreeBaseNodeConstructor extends Constructor<RgthreeBaseNode> {
static type: string;
static category: string;
static comfyClass: string;
static exposedActions: string[];
}
export interface RgthreeBaseVirtualNodeConstructor extends Constructor<RgthreeBaseVirtualNode> {
static type: string;
static category: string;
static _category: string;
}
export interface RgthreeBaseServerNodeConstructor extends Constructor<RgthreeBaseServerNode> {
static nodeType: ComfyNodeConstructor;
static nodeData: ComfyObjectInfo;
static __registeredForOverride__: boolean;
onRegisteredForOverride(comfyClass: any, rgthreeClass: any) : void;
}
export type RgthreeModelInfoDetails = {
file?: string;
path?: string;
hasInfoFile?: boolean;
image?: string;
}
export type RgthreeModelInfo = RgthreeModelInfoDetails & {
name?: string;
type?: string;
baseModel?: string;
baseModelFile?: string;
links?: string[];
strengthMin?: number;
strengthMax?: number;
triggerWords?: string[];
trainedWords?: {
word: string;
count?: number;
civitai?: boolean
user?: boolean
}[];
description?: string;
sha256?: string;
path?: string;
images?: {
url: string;
civitaiUrl?: string;
steps?: string|number;
cfg?: string|number;
type?: 'image'|'video';
sampler?: string;
model?: string;
seed?: string;
negative?: string;
positive?: string;
resources?: {name?: string, type?: string, weight?: string|number}[];
}[]
userTags?: string[];
userNote?: string;
raw?: any;
// This one is just on the client.
filterDir?: string;
}

View File

@@ -0,0 +1 @@
import 'web-tree-sitter';