feat: support dev-only nodes (#8359)

## Summary

Support `dev_only` property to node definitions that hides nodes from
search and menus unless dev mode is enabled. Dev-only nodes display a
"DEV" badge when visible.

This functionality is primarily intended to support unit-testing nodes
on Comfy Cloud, but also has other uses.

## Changes

- **What**: Nodes flagged as dev_only in the node schema will only
appear in search and menus if Dev Mode is on.

## Screenshots (if applicable)

With Dev Mode off:
<img width="2189" height="1003" alt="image"
src="https://github.com/user-attachments/assets/a08e1fd7-dca9-4ce1-9964-5f4f3b7b95ac"
/>

With Dev Mode on:
<img width="2201" height="1066" alt="image"
src="https://github.com/user-attachments/assets/7fe6cd1f-f774-4f48-b604-a528e286b584"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8359-feat-support-dev-only-nodes-2f66d73d36508102839ee7cd66a26129)
by [Unito](https://www.unito.io)
This commit is contained in:
guill
2026-01-28 19:41:45 -08:00
committed by GitHub
parent 2103dcc788
commit 9be853f6b5
8 changed files with 60 additions and 12 deletions

View File

@@ -1,9 +1,10 @@
import axios from 'axios'
import _ from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { computed, ref, watchEffect } from 'vue'
import { isProxyWidget } from '@/core/graph/subgraph/proxyWidget'
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import { transformNodeDefV1ToV2 } from '@/schemas/nodeDef/migration'
import type {
@@ -17,6 +18,7 @@ import type {
ComfyOutputTypesSpec as ComfyOutputSpecV1,
PriceBadge
} from '@/schemas/nodeDefSchema'
import { useSettingStore } from '@/platform/settings/settingStore'
import { NodeSearchService } from '@/services/nodeSearchService'
import { useSubgraphStore } from '@/stores/subgraphStore'
import { NodeSourceType, getNodeSource } from '@/types/nodeSource'
@@ -41,6 +43,7 @@ export class ComfyNodeDefImpl
readonly help: string
readonly deprecated: boolean
readonly experimental: boolean
readonly dev_only: boolean
readonly output_node: boolean
readonly api_node: boolean
/**
@@ -133,6 +136,7 @@ export class ComfyNodeDefImpl
this.deprecated = obj.deprecated ?? obj.category === ''
this.experimental =
obj.experimental ?? obj.category.startsWith('_for_testing')
this.dev_only = obj.dev_only ?? false
this.output_node = obj.output_node
this.api_node = !!obj.api_node
this.input = obj.input ?? {}
@@ -174,6 +178,7 @@ export class ComfyNodeDefImpl
get nodeLifeCycleBadgeText(): string {
if (this.deprecated) return '[DEPR]'
if (this.experimental) return '[BETA]'
if (this.dev_only) return '[DEV]'
return ''
}
}
@@ -299,12 +304,27 @@ export interface NodeDefFilter {
}
export const useNodeDefStore = defineStore('nodeDef', () => {
const settingStore = useSettingStore()
const nodeDefsByName = ref<Record<string, ComfyNodeDefImpl>>({})
const nodeDefsByDisplayName = ref<Record<string, ComfyNodeDefImpl>>({})
const showDeprecated = ref(false)
const showExperimental = ref(false)
const showDevOnly = computed(() => settingStore.get('Comfy.DevMode'))
const nodeDefFilters = ref<NodeDefFilter[]>([])
// Update skip_list on all registered node types when dev mode changes
// This ensures LiteGraph's getNodeTypesCategories/getNodeTypesInCategory
// correctly filter dev-only nodes from the right-click context menu
watchEffect(() => {
const devModeEnabled = showDevOnly.value
for (const nodeType of Object.values(LiteGraph.registered_node_types)) {
if (nodeType.nodeData?.dev_only) {
nodeType.skip_list = !devModeEnabled
}
}
})
const nodeDefs = computed(() => {
const subgraphStore = useSubgraphStore()
// Blueprints first for discoverability in the node library sidebar
@@ -422,6 +442,14 @@ export const useNodeDefStore = defineStore('nodeDef', () => {
predicate: (nodeDef) => showExperimental.value || !nodeDef.experimental
})
// Dev-only nodes filter
registerNodeDefFilter({
id: 'core.dev_only',
name: 'Hide Dev-Only Nodes',
description: 'Hides nodes marked as dev-only unless dev mode is enabled',
predicate: (nodeDef) => showDevOnly.value || !nodeDef.dev_only
})
// Subgraph nodes filter
// Filter out litegraph typed subgraphs, saved blueprints are added in separately
registerNodeDefFilter({
@@ -446,6 +474,7 @@ export const useNodeDefStore = defineStore('nodeDef', () => {
nodeDefsByDisplayName,
showDeprecated,
showExperimental,
showDevOnly,
nodeDefFilters,
nodeDefs,