-
Notifications
You must be signed in to change notification settings - Fork 419
Add support for growable inputs #6830
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This also fixes a bug with links to widgetInputs being broken on reload
Sorry Alex, I've failed you
Does not work well with serialization currently Tries to solve the hard problem of multiple inputs in a group, but has not yet been tested While implementation attempts to account for groups containing widgets, no attempt has been made to do removal or re-ordering of inputs. (To maintain group appearance, this will likely require empty widgets for group inputs as well)
📝 WalkthroughWalkthroughMoves match-type and autogrow dynamic-input logic into core dynamicWidgets, adding applyDynamicInputs, handlers for match-type and autogrow, type-management helpers, schema updates (zAutogrowOptions, exported zComfyInputsSpec), service integration, LGraphNode field addition, spliceInputs removal, and tests for autogrow. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Service as litegraphService
participant Dynamic as dynamicWidgets
participant Node as LGraphNode
participant Handler as DynamicHandler
Service->>Dynamic: applyDynamicInputs(node, inputSpec)
alt dynamic inputSpec (autogrow / matchType)
Dynamic->>Handler: dispatch to handler
Handler->>Node: add/remove/relink inputs, update comfyMatchType, change output types
Handler-->>Dynamic: complete
Dynamic-->>Service: return true (skip default socket creation)
else static inputSpec
Dynamic-->>Service: return false (proceed with socket creation)
end
Service->>Node: create input socket (if not skipped)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 11/26/2025, 02:48:19 AM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Test Results⏰ Completed at: 11/26/2025, 02:56:45 AM UTC 📈 Summary
📊 Test Reports by Browser
🎉 Click on the links above to view detailed test results for each browser configuration. |
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 3.19 MB (baseline 3.18 MB) • 🔴 +7.47 kBMain entry bundles and manifests
Status: 3 added / 3 removed Graph Workspace — 944 kB (baseline 944 kB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 1 added / 1 removed Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 6 added / 6 removed UI Components — 139 kB (baseline 139 kB) • ⚪ 0 BReusable component library chunks
Status: 9 added / 9 removed Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 BStores, services, APIs, and repositories
Status: 3 added / 3 removed Utilities & Hooks — 2.94 kB (baseline 2.94 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 1 added / 1 removed Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Status: 5 added / 5 removed Other — 3.84 MB (baseline 3.84 MB) • ⚪ 0 BBundles that do not match a named category
Status: 23 added / 23 removed |
🔧 Auto-fixes AppliedThis PR has been automatically updated to fix linting and formatting issues.
Changes made:
|
matchType is no longer implemented as an extension and is now located with the other dynamic inputs. matchType no longer needs to create a record of groups before creation. This allows for match type inputs to be dynamically added and removed. Note that output dynamic types still need to be declared in advance. This is reasonably solvable in the future, but requires schema changes.
None of the changes are ideal, but they fix bugs and prevent us from being locked into a bad format in the future
49f4a8c to
c76b8c3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (4)
src/core/graph/widgets/dynamicWidgets.ts (4)
22-35: Consider adding JSDoc for thezAutogrowOptionsschema.The schema structure is clear, but documenting the purpose of each field (especially the relationship between
names,prefix,min, andmax) would improve maintainability.
338-348: Magic timeout value and potential timing issues.The
setTimeout(..., 50)pattern appears multiple times in this file. Consider:
- Extracting the magic number to a named constant to document its purpose
- Adding a comment explaining why this delay is necessary
This timing-based approach could be fragile if the event loop is under heavy load.
+const MATCH_TYPE_INIT_DELAY_MS = 50 // Allow graph to settle before triggering initial type calculation + //TODO: instead apply on output add? //ensure outputs get updated const index = node.inputs.length - 1 const input = node.inputs.at(-1)! setTimeout( () => node.onConnectionsChange!( LiteGraph.INPUT, index, false, undefined, input ), - 50 + MATCH_TYPE_INIT_DELAY_MS )
466-497: Complex connection swap detection logic - document the reasoning.The
pendingConnectionandswappingConnectionflags with 50ms timeouts form a state machine to handle connection swaps. This is clever but non-obvious. Adding a brief comment explaining the connection swap scenario would help future maintainers.+// Connection swap detection: +// When a connection is "swapped" (dragged from one input to another), litegraph fires +// disconnect then connect events in rapid succession. We track pendingConnection to +// detect this pattern and avoid prematurely removing input groups. let pendingConnection: number | undefined let swappingConnection = false
246-254: Usees-toolkit/compatintersection instead of custom implementation.The custom
intersectionfunction (lines 246-254) duplicates functionality available in es-toolkit. Replace with:
import { intersection } from 'es-toolkit/compat'- Remove the custom function definition
The calling pattern at line 240 remains unchanged since both have matching variadic signatures. This aligns with coding guidelines to use es-toolkit for utility functions.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/core/graph/widgets/dynamicWidgets.ts(5 hunks)src/extensions/core/index.ts(0 hunks)src/extensions/core/matchType.ts(0 hunks)src/schemas/nodeDefSchema.ts(1 hunks)src/services/litegraphService.ts(2 hunks)tests-ui/tests/widgets/dynamicCombo.test.ts(3 hunks)
💤 Files with no reviewable changes (2)
- src/extensions/core/matchType.ts
- src/extensions/core/index.ts
🧰 Additional context used
📓 Path-based instructions (14)
**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json
Files:
src/services/litegraphService.tstests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Use es-toolkit for utility functions
Files:
src/services/litegraphService.tstests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use TypeScript for type safety
**/*.{ts,tsx}: Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/services/litegraphService.tstests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (.cursorrules)
Implement proper error handling in components and services
**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in.prettierrc
Organize imports by sorting and grouping by plugin, and runpnpm formatbefore committing
Files:
src/services/litegraphService.tstests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/services/litegraphService.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/services/litegraphService.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/services/litegraphService.tstests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,vue}: Useconst settingStore = useSettingStore()andsettingStore.get('Comfy.SomeSetting')to retrieve settings in TypeScript/Vue files
Useawait settingStore.set('Comfy.SomeSetting', newValue)to update settings in TypeScript/Vue files
Check server capabilities usingapi.serverSupportsFeature('feature_name')before using enhanced features
Useapi.getServerFeature('config_name', defaultValue)to retrieve server feature configurationEnforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates
Files:
src/services/litegraphService.tstests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
UsedefaultsByInstallVersionproperty for gradual feature rollout based on version in settings configuration
Files:
src/services/litegraphService.tstests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
src/**/{services,composables}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/{services,composables}/**/*.{ts,tsx}: Useapi.apiURL()for backend endpoints instead of constructing URLs directly
Useapi.fileURL()for static file access instead of constructing URLs directly
Files:
src/services/litegraphService.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/services/litegraphService.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/services/litegraphService.tssrc/core/graph/widgets/dynamicWidgets.tssrc/schemas/nodeDefSchema.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/widgets/dynamicCombo.test.ts
**/*.{test,spec}.{ts,tsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Unit and component tests should be located in
tests-ui/or co-located with components assrc/components/**/*.{test,spec}.ts; E2E tests should be inbrowser_tests/
Files:
tests-ui/tests/widgets/dynamicCombo.test.ts
🧠 Learnings (8)
📚 Learning: 2025-11-24T19:47:56.344Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.344Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup
Applied to files:
src/services/litegraphService.tstests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:47:56.344Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.344Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : When writing tests for subgraph-related code, always import from the barrel export at `@/lib/litegraph/src/litegraph` to avoid circular dependency issues
Applied to files:
src/services/litegraphService.tstests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:47:56.344Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.344Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:03.239Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.239Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:03.239Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.239Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:23.077Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.077Z
Learning: Use Vitest (with happy-dom) for unit and component tests, and Playwright for E2E tests
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:09.286Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.286Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:09.286Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.286Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
🧬 Code graph analysis (2)
src/services/litegraphService.ts (1)
src/core/graph/widgets/dynamicWidgets.ts (1)
applyDynamicInputs(188-196)
tests-ui/tests/widgets/dynamicCombo.test.ts (2)
src/lib/litegraph/src/LGraphNode.ts (4)
LGraphNode(209-211)LGraphNode(221-4167)LGraphNode(728-736)LGraphNode(738-744)src/schemas/nodeDef/migration.ts (1)
transformInputSpecV1ToV2(96-137)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: lint-and-format
- GitHub Check: test
- GitHub Check: collect
- GitHub Check: setup
🔇 Additional comments (6)
src/schemas/nodeDefSchema.ts (1)
184-190: LGTM! ExportingzComfyInputsSpecfor reuse in dynamic widgets.This export enables the dynamic widgets module to validate autogrow and dynamic combo input specs against the same schema used for node definitions, maintaining consistency.
tests-ui/tests/widgets/dynamicCombo.test.ts (2)
43-57: LGTM! Well-structured test helpers.The
addAutogrowandconnectInputhelpers encapsulate common test setup patterns, making the test cases more readable. The use oftransformInputSpecV1ToV2is consistent with the existingaddDynamicCombohelper.
106-171: Comprehensive test coverage for autogrow functionality.The test suite covers essential scenarios:
- Naming strategies (prefix and explicit names)
- Minimum input enforcement
- Growth up to maximum when connections are added
- Reduction behavior on disconnection with connection bubbling
The assertions correctly verify the expected input counts and name assignments.
src/core/graph/widgets/dynamicWidgets.ts (2)
188-196: LGTM! Clean dispatcher pattern for dynamic inputs.The
applyDynamicInputsfunction provides a clear interface for the litegraph service, returning a boolean to indicate whether the input was handled dynamically.
117-128: LGTM! Link preservation logic for dynamic combo changes.The logic correctly preserves connections when switching between compatible input types by:
- Checking if the old input exists and has a compatible type
- Transferring the link reference before removing the old input
This addresses the reload issue mentioned in the PR objectives.
src/services/litegraphService.ts (1)
96-100: Now I'll search the repository to verify the concerns about the OR condition logic:Based on the script output from the first execution and my analysis, I can now generate the rewritten review comment. The script confirmed thatCOMFY_AUTOGROW_V3andCOMFY_MATCHTYPE_V3are registered in a handler map insrc/core/graph/widgets/dynamicWidgets.ts, not as widget constructors. This means they won't have widget constructors that could cause the short-circuit issue.The OR condition precedence is correct and not a concern.
The condition properly handles the two cases:
- If a widget constructor exists AND forceInput is not set → return (create as widget)
- If the first condition is false → call
applyDynamicInputswhich handlesCOMFY_AUTOGROW_V3andCOMFY_MATCHTYPE_V3types through a handler map, not via widget constructorsSince
COMFY_AUTOGROW_V3andCOMFY_MATCHTYPE_V3are handled via theapplyDynamicInputshandler map (not widget constructors), they will never be short-circuited by the first condition. The logic is sound.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/core/graph/widgets/dynamicWidgets.ts (1)
75-117: Verified: Link target_slot desync risk is real but conditional on node structureThe concern is valid but applies to a specific scenario. After analyzing the code:
removeInput doesn't auto-sync: When
node.removeInput()is called (lines 130–137), it shifts all subsequent inputs' array indices downward, but doesn't update theirlink.target_slotvalues.Partial re-sync by spliceInputs: The subsequent
spliceInputscalls (lines 150, 160) only re-synctarget_slotfor inputs from theirstartIndexonward. Specifically, line 160's call syncs only frominputInsertionPoint(the position after the combo widget).Gap for non-dynamic inputs: If the node has inputs after the dynamic block that already have links, and the dynamic inputs before them are removed, those non-dynamic inputs' indices shift but their
target_slotvalues aren't updated byspliceInputs. This creates a mismatch:input.linkreferences a link ID whoselink.target_slotnow points elsewhere.Confirmation from autogrow code: Lines 449–458 show the
dynamicInputsfunction explicitly re-syncstarget_slotafter manipulatinginput.linkdirectly, confirming the need for this invariant.The proposed fix is sound and follows the defensive pattern already used elsewhere in the codebase.
🧹 Nitpick comments (3)
src/core/graph/widgets/dynamicWidgets.ts (3)
198-226: Guard against mutatingoutput.linkswhile iterating
changeOutputTypewalksoutput.linkswhile potentially disconnecting links:for (const link_id of output.links ?? []) { // ... if (!keep && subgraphOutput) subgraphOutput.disconnect() else if (!keep && inputNode) inputNode.disconnectInput(link.target_slot) // ... }If
disconnectmutatesoutput.links, you can end up skipping some entries. A small defensive tweak avoids this:- for (const link_id of output.links ?? []) { + for (const link_id of [...(output.links ?? [])]) {The type‑combining helpers (
isStrings,combineTypes,intersection) look reasonable and correctly treat'*'as a wildcard.Also applies to: 228-254
256-349: Match‑type recomputation logic looks correct; consider softer handling for invalid connectionsThe match‑type handler:
- Builds
comfyMatchTypegroups pertemplate_id.- On connection changes, computes compatible per‑input and per‑output types via
combineTypes.- Uses
changeOutputTypeso invalid downstream connections get dropped when output types tighten.This is a solid approach and nicely reuses the shared helpers.
One behavioral nit: when
combineTypesreturnsundefined, the code throwsnew Error('invalid connection'). That will surface as a runtime error for what is essentially a user drag‑and‑drop mistake. A softer alternative would be to:
- Reject or immediately disconnect the attempted link, and
- Return early without throwing.
That would keep UX smoother while still enforcing type safety.
351-498: Autogrow implementation is robust; only minor polish possibleThe autogrow handler:
- Validates its spec via
zAutogrowOptions.- Correctly constructs V2 inputs, enforces the single‑template constraint, and tracks groups by logical ordinal.
- Grows on connect and shrinks on fully‑disconnected trailing groups while respecting
min/max, and carefully preserves link wiring via the bubble‑swap loop.Overall this is a solid, well‑structured implementation for a complex behavior. The only minor polish you might consider (not urgent):
- Extracting the link bubble‑swap plus “remove last empty group” logic into a small helper for readability.
- Documenting the rationale for the
50ms timeouts (pendingConnection/swappingConnection) since they’re subtle and timing‑dependent.Functionally, nothing here blocks merging.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/core/graph/widgets/dynamicWidgets.ts(5 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Use es-toolkit for utility functions
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use TypeScript for type safety
**/*.{ts,tsx}: Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (.cursorrules)
Implement proper error handling in components and services
**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in.prettierrc
Organize imports by sorting and grouping by plugin, and runpnpm formatbefore committing
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,vue}: Useconst settingStore = useSettingStore()andsettingStore.get('Comfy.SomeSetting')to retrieve settings in TypeScript/Vue files
Useawait settingStore.set('Comfy.SomeSetting', newValue)to update settings in TypeScript/Vue files
Check server capabilities usingapi.serverSupportsFeature('feature_name')before using enhanced features
Useapi.getServerFeature('config_name', defaultValue)to retrieve server feature configurationEnforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
UsedefaultsByInstallVersionproperty for gradual feature rollout based on version in settings configuration
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/core/graph/widgets/dynamicWidgets.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: lint-and-format
- GitHub Check: test
- GitHub Check: collect
- GitHub Check: setup
🔇 Additional comments (2)
src/core/graph/widgets/dynamicWidgets.ts (2)
22-35: Schema definitions for match-type and autogrow look solidThe
MatchTypeNodeaugmentation and both zod schemas (zAutogrowOptions,zDynamicComboInputSpec) are well-typed and align with the described backend behavior (more lenient frontendmin, explicit options structure). No functional issues spotted here.Also applies to: 37-47
180-196: Dynamic input dispatcher is clean and extensibleThe
dynamicInputsmap plusapplyDynamicInputsboolean return is a nice, simple dispatcher and keeps the per‑type logic contained in dedicated handlers. This should scale well as more dynamic input types are added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/core/graph/widgets/dynamicWidgets.ts (1)
75-135: Reconnecting dynamicCombo inputs should also updateLLink.target_slot(graph state may become inconsistent).When reusing existing links for new dynamic inputs, only
node.inputs.at(-1)!.linkis updated. The correspondinggraph.links[linkId].target_slotis left pointing at the old slot index, and the old input is later removed. This can leave links effectively attached to the wrong input index and desynchronizeinputs[*].linkfromgraph.links[*].target_slot, especially afterremoveInput/spliceInputsreindexing.You can fix this by updating the link’s
target_slot(and guarding null links) when migrating the connection:- if ( - !inputsToRemove[name] || - Array.isArray(inputType![name][0]) || - !LiteGraph.isValidConnection( - inputsToRemove[name].type, - inputType![name][0] - ) - ) - continue - node.inputs.at(-1)!.link = inputsToRemove[name].link - inputsToRemove[name].link = null + const previousInput = inputsToRemove[name] + if ( + !previousInput || + Array.isArray(inputType![name][0]) || + !LiteGraph.isValidConnection( + previousInput.type, + inputType![name][0] + ) + ) + continue + const linkId = previousInput.link + if (linkId == null) continue + const newInputIndex = node.inputs.length - 1 + node.inputs[newInputIndex].link = linkId + previousInput.link = null + const link = node.graph?.links?.[linkId] + if (link) link.target_slot = newInputIndexThis keeps the graph’s link metadata in sync with the slots you’re actually wiring.
🧹 Nitpick comments (1)
src/core/graph/widgets/dynamicWidgets.ts (1)
469-500: ApplyuseChainCallbacktonode.onConnectInputto prevent state collision if multiple autogrow specs exist on one node.The architecture confirms the review's concern:
addInputs()loops through input specs (line 208 in litegraphService.ts), callingaddInputSocketfor each. If multiple specs have typeCOMFY_AUTOGROW_V3, thenapplyAutogrowis invoked multiple times on the same node, each replacingnode.onConnectInputwithout proper chaining. This leaves earlier autogrow handlers'pendingConnection/swappingConnectionflags unreachable in subsequent wrappers, causing disconnection-swap logic to misfire.While
onConnectionsChangeis correctly chained viauseChainCallback(line 481),onConnectInputuses manual replacement (line 469). Applying the sameuseChainCallbackpattern toonConnectInput(lines 468–477) ensures all autogrow handlers maintain consistent state visibility and safe callback stacking.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/core/graph/widgets/dynamicWidgets.ts(6 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Use es-toolkit for utility functions
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use TypeScript for type safety
**/*.{ts,tsx}: Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (.cursorrules)
Implement proper error handling in components and services
**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in.prettierrc
Organize imports by sorting and grouping by plugin, and runpnpm formatbefore committing
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,vue}: Useconst settingStore = useSettingStore()andsettingStore.get('Comfy.SomeSetting')to retrieve settings in TypeScript/Vue files
Useawait settingStore.set('Comfy.SomeSetting', newValue)to update settings in TypeScript/Vue files
Check server capabilities usingapi.serverSupportsFeature('feature_name')before using enhanced features
Useapi.getServerFeature('config_name', defaultValue)to retrieve server feature configurationEnforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
UsedefaultsByInstallVersionproperty for gradual feature rollout based on version in settings configuration
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/core/graph/widgets/dynamicWidgets.ts
🪛 ESLint
src/core/graph/widgets/dynamicWidgets.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/tGmZzPPEVU'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at ExportMap.get (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/export-map.js:88:22)
at processBodyStatement (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:9:31)
at Program (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:100:21)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/namespace)
[error] 1-1: Resolve error: EACCES: permission denied, open '/KhMLIotFGY'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-unresolved.js:31:34)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/no-unresolved)
[error] 1-1: Resolve error: EACCES: permission denied, open '/tlimgntOgL'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at importType (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/import-type.js:126:63)
at checkImportForRelativePackage (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:15:38)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:59:40
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/no-relative-packages)
[error] 1-1: Unable to resolve path to module 'es-toolkit'.
(import-x/no-unresolved)
[error] 2-2: Unable to resolve path to module 'zod'.
(import-x/no-unresolved)
[error] 4-4: Unable to resolve path to module '@/composables/functional/useChainCallback'.
(import-x/no-unresolved)
[error] 5-5: Unable to resolve path to module '@/lib/litegraph/src/types/globalEnums'.
(import-x/no-unresolved)
[error] 12-12: Unable to resolve path to module '@/lib/litegraph/src/litegraph'.
(import-x/no-unresolved)
[error] 14-14: Unable to resolve path to module '@/schemas/nodeDef/migration'.
(import-x/no-unresolved)
[error] 17-17: Unable to resolve path to module '@/schemas/nodeDefSchema'.
(import-x/no-unresolved)
[error] 18-18: Unable to resolve path to module '@/services/litegraphService'.
(import-x/no-unresolved)
[error] 19-19: Unable to resolve path to module '@/scripts/app'.
(import-x/no-unresolved)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
- GitHub Check: deploy-and-comment
- GitHub Check: lint-and-format
- GitHub Check: test
- GitHub Check: collect
- GitHub Check: setup
| function inputDisconnected(index: number) { | ||
| const input = node.inputs[index] | ||
| if (trackedInputs.length === 1) return | ||
| const groupIndex = trackedInputs.findIndex((ig) => | ||
| ig.some((inputName) => inputName === input.name) | ||
| ) | ||
| if (groupIndex == -1) throw new Error('Failed to find group') | ||
| if ( | ||
| trackedInputs[groupIndex].some( | ||
| (inputName) => nameToInput(inputName).link != null | ||
| ) | ||
| ) | ||
| return | ||
| if (groupIndex + 1 < (min ?? 0)) return | ||
| //For each group from here to last group, bubble swap links | ||
| for (let column = 0; column < trackedInputs[0].length; column++) { | ||
| let prevInput = nameToInputIndex(trackedInputs[groupIndex][column]) | ||
| for (let i = groupIndex + 1; i < trackedInputs.length; i++) { | ||
| const curInput = nameToInputIndex(trackedInputs[i][column]) | ||
| const linkId = node.inputs[curInput].link | ||
| node.inputs[prevInput].link = linkId | ||
| const link = linkId && node.graph?.links?.[linkId] | ||
| if (link) link.target_slot = prevInput | ||
| prevInput = curInput | ||
| } | ||
| node.inputs[prevInput].link = null | ||
| } | ||
| if ( | ||
| trackedInputs.at(-2) && | ||
| !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) | ||
| ) | ||
| removeInputGroup(trackedInputs.at(-1)![0]) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Autogrow min can be violated when shrinking groups; consider enforcing it where groups are removed.
inputDisconnected prevents shrink when groupIndex + 1 < (min ?? 0), but the final removal step only checks that the second-to-last group has no links. With min > 1, you can end up with fewer groups than min once trailing groups are all empty (e.g., starting with min = 2, disconnecting so both groups are empty).
You can keep the “at most one trailing empty group” behavior while honoring min by adding a length check before actually dropping the last group:
- if (
- trackedInputs.at(-2) &&
- !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link)
- )
- removeInputGroup(trackedInputs.at(-1)![0])
+ if (
+ trackedInputs.at(-2) &&
+ !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) &&
+ trackedInputs.length - 1 >= (min ?? 0)
+ )
+ removeInputGroup(trackedInputs.at(-1)![0])This keeps at least min autogrow groups present even after aggressive disconnects.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function inputDisconnected(index: number) { | |
| const input = node.inputs[index] | |
| if (trackedInputs.length === 1) return | |
| const groupIndex = trackedInputs.findIndex((ig) => | |
| ig.some((inputName) => inputName === input.name) | |
| ) | |
| if (groupIndex == -1) throw new Error('Failed to find group') | |
| if ( | |
| trackedInputs[groupIndex].some( | |
| (inputName) => nameToInput(inputName).link != null | |
| ) | |
| ) | |
| return | |
| if (groupIndex + 1 < (min ?? 0)) return | |
| //For each group from here to last group, bubble swap links | |
| for (let column = 0; column < trackedInputs[0].length; column++) { | |
| let prevInput = nameToInputIndex(trackedInputs[groupIndex][column]) | |
| for (let i = groupIndex + 1; i < trackedInputs.length; i++) { | |
| const curInput = nameToInputIndex(trackedInputs[i][column]) | |
| const linkId = node.inputs[curInput].link | |
| node.inputs[prevInput].link = linkId | |
| const link = linkId && node.graph?.links?.[linkId] | |
| if (link) link.target_slot = prevInput | |
| prevInput = curInput | |
| } | |
| node.inputs[prevInput].link = null | |
| } | |
| if ( | |
| trackedInputs.at(-2) && | |
| !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) | |
| ) | |
| removeInputGroup(trackedInputs.at(-1)![0]) | |
| } | |
| function inputDisconnected(index: number) { | |
| const input = node.inputs[index] | |
| if (trackedInputs.length === 1) return | |
| const groupIndex = trackedInputs.findIndex((ig) => | |
| ig.some((inputName) => inputName === input.name) | |
| ) | |
| if (groupIndex == -1) throw new Error('Failed to find group') | |
| if ( | |
| trackedInputs[groupIndex].some( | |
| (inputName) => nameToInput(inputName).link != null | |
| ) | |
| ) | |
| return | |
| if (groupIndex + 1 < (min ?? 0)) return | |
| //For each group from here to last group, bubble swap links | |
| for (let column = 0; column < trackedInputs[0].length; column++) { | |
| let prevInput = nameToInputIndex(trackedInputs[groupIndex][column]) | |
| for (let i = groupIndex + 1; i < trackedInputs.length; i++) { | |
| const curInput = nameToInputIndex(trackedInputs[i][column]) | |
| const linkId = node.inputs[curInput].link | |
| node.inputs[prevInput].link = linkId | |
| const link = linkId && node.graph?.links?.[linkId] | |
| if (link) link.target_slot = prevInput | |
| prevInput = curInput | |
| } | |
| node.inputs[prevInput].link = null | |
| } | |
| if ( | |
| trackedInputs.at(-2) && | |
| !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) && | |
| trackedInputs.length - 1 >= (min ?? 0) | |
| ) | |
| removeInputGroup(trackedInputs.at(-1)![0]) | |
| } |
🤖 Prompt for AI Agents
In src/core/graph/widgets/dynamicWidgets.ts around lines 435 to 467, the final
removal of the trailing empty group can violate the autogrow min constraint;
change the final removal condition so it only removes the last group if
trackedInputs.length > (min ?? 0) in addition to the existing check that the
second-to-last group is empty — this ensures you never drop below the configured
min groups while keeping the single trailing-empty-group behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
src/core/graph/widgets/dynamicWidgets.ts (2)
389-393: Guard against undefined names when ordinal exceeds names array length.This is the same concern flagged in the previous review. When
namesis provided butordinal >= names.length,names[ordinal]returnsundefined, producing inputs with undefined names that break lookup and error messages.Apply this fix to use optional chaining with nullish coalescing:
const namedSpec = { ...input, - name: names ? names[ordinal] : (prefix ?? '') + ordinal, + name: names?.[ordinal] ?? (prefix ?? '') + ordinal, isOptional: ordinal >= (min ?? 0) || input.isOptional }
463-467: Enforce min constraint when removing trailing empty groups.This is the same concern flagged in the previous review. The current logic can reduce the group count below
minwhen multiple trailing groups become empty. Add a length check before removal.Apply this fix to respect the minimum constraint:
if ( trackedInputs.at(-2) && - !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) + !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) && + trackedInputs.length > (min ?? 0) ) removeInputGroup(trackedInputs.at(-1)![0])
🧹 Nitpick comments (4)
src/core/graph/widgets/dynamicWidgets.ts (4)
197-197: Consider moving validation into dispatcher.The TODO suggests centralizing parsing/validation in
applyDynamicInputs. This would improve consistency and reduce duplication across handlers.Would you like me to generate a refactored version that centralizes the validation logic?
270-270: Replace informal comment with technical explanation.The "Sorry" comment is unprofessional. Replace with a technical explanation of why the type assertion is necessary.
- //Sorry + // Type assertion required to access dynamic match-type tracking const augmentedNode = node as MatchTypeNode
342-352: Document setTimeout workaround or find alternative.The
setTimeoutis used to ensure outputs are updated after input initialization. While it works, this timing-dependent approach is fragile. Consider whether there's a more deterministic way to trigger the update, such as an explicit initialization callback or flag.If this timing workaround is necessary due to LiteGraph's lifecycle, add a more detailed comment explaining why synchronous invocation doesn't work and what race condition this prevents.
372-372: Multi-input autogrow is not yet implemented.The current implementation only supports single-input templates (
inputsV2.length !== 1throws). This limitation should be documented in the function's JSDoc or at the call site, and consideration given to either implementing multi-input support or validating at the spec level.Is multi-input autogrow planned for a future release? If so, consider tracking this with a GitHub issue rather than a runtime error.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/core/graph/widgets/dynamicWidgets.ts(6 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Use es-toolkit for utility functions
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use TypeScript for type safety
**/*.{ts,tsx}: Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (.cursorrules)
Implement proper error handling in components and services
**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in.prettierrc
Organize imports by sorting and grouping by plugin, and runpnpm formatbefore committing
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,vue}: Useconst settingStore = useSettingStore()andsettingStore.get('Comfy.SomeSetting')to retrieve settings in TypeScript/Vue files
Useawait settingStore.set('Comfy.SomeSetting', newValue)to update settings in TypeScript/Vue files
Check server capabilities usingapi.serverSupportsFeature('feature_name')before using enhanced features
Useapi.getServerFeature('config_name', defaultValue)to retrieve server feature configurationEnforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
UsedefaultsByInstallVersionproperty for gradual feature rollout based on version in settings configuration
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/core/graph/widgets/dynamicWidgets.ts
🧬 Code graph analysis (1)
src/core/graph/widgets/dynamicWidgets.ts (6)
src/schemas/nodeDefSchema.ts (3)
zBaseInputOptions(22-35)zComfyInputsSpec(184-190)InputSpec(241-241)src/lib/litegraph/src/litegraph.ts (1)
LiteGraph(17-17)src/scripts/app.ts (1)
app(1708-1708)src/services/litegraphService.ts (1)
useLitegraphService(74-906)src/composables/functional/useChainCallback.ts (1)
useChainCallback(24-35)src/schemas/nodeDef/migration.ts (1)
transformInputSpecV1ToV2(96-137)
🪛 ESLint
src/core/graph/widgets/dynamicWidgets.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/QWWiZvqQDI'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at ExportMap.get (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/export-map.js:88:22)
at processBodyStatement (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:9:31)
at Program (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:100:21)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/namespace)
[error] 1-1: Resolve error: EACCES: permission denied, open '/JjenYNDLbA'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-unresolved.js:31:34)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/no-unresolved)
[error] 1-1: Resolve error: EACCES: permission denied, open '/ZwEuTLPljw'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at importType (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/import-type.js:126:63)
at checkImportForRelativePackage (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:15:38)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:59:40
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/no-relative-packages)
[error] 1-1: Unable to resolve path to module 'es-toolkit'.
(import-x/no-unresolved)
[error] 2-2: Unable to resolve path to module 'zod'.
(import-x/no-unresolved)
[error] 4-4: Unable to resolve path to module '@/composables/functional/useChainCallback'.
(import-x/no-unresolved)
[error] 5-5: Unable to resolve path to module '@/lib/litegraph/src/types/globalEnums'.
(import-x/no-unresolved)
[error] 12-12: Unable to resolve path to module '@/lib/litegraph/src/litegraph'.
(import-x/no-unresolved)
[error] 14-14: Unable to resolve path to module '@/schemas/nodeDef/migration'.
(import-x/no-unresolved)
[error] 17-17: Unable to resolve path to module '@/schemas/nodeDefSchema'.
(import-x/no-unresolved)
[error] 18-18: Unable to resolve path to module '@/services/litegraphService'.
(import-x/no-unresolved)
[error] 19-19: Unable to resolve path to module '@/scripts/app'.
(import-x/no-unresolved)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: playwright-tests-chromium-sharded (6, 8)
- GitHub Check: playwright-tests-chromium-sharded (8, 8)
- GitHub Check: playwright-tests-chromium-sharded (7, 8)
- GitHub Check: playwright-tests-chromium-sharded (4, 8)
- GitHub Check: playwright-tests-chromium-sharded (3, 8)
- GitHub Check: playwright-tests-chromium-sharded (5, 8)
- GitHub Check: playwright-tests-chromium-sharded (2, 8)
- GitHub Check: playwright-tests (chromium-0.5x)
- GitHub Check: playwright-tests-chromium-sharded (1, 8)
- GitHub Check: playwright-tests (mobile-chrome)
- GitHub Check: playwright-tests (chromium-2x)
🔇 Additional comments (5)
src/core/graph/widgets/dynamicWidgets.ts (5)
22-35: LGTM: Well-structured type definitions and schemas.The MatchTypeNode augmentation and zAutogrowOptions schema are well-designed and properly leverage Zod for validation.
117-128: LGTM: Robust link preservation logic.The conditional link preservation based on type compatibility is well-implemented, ensuring connections are only maintained when valid.
202-230: LGTM: Comprehensive output type change handling.The function properly validates and cleans up connections when output types change, handling both regular inputs and subgraph outputs correctly.
232-258: LGTM: Clean type combination utilities.Good use of
es-toolkit'swithoututility and proper TypeScript type guards. The intersection logic correctly computes common types across all input sets.
470-501: LGTM: Proper connection state management.The
onConnectInputandonConnectionsChangewiring correctly handles connection swapping and prevents spurious disconnection events. The use ofuseChainCallbackto compose callbacks is clean and maintains existing behavior.
| ).template | ||
| const typedSpec = { ...inputSpec, type: allowed_types } | ||
| addNodeInput(node, typedSpec) | ||
| //Sorry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are not forgiven.
| augmentedNode.comfyMatchType[template_id] ??= {} | ||
| augmentedNode.comfyMatchType[template_id][name] = allowed_types |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is where we'd get a runtime error.
| return node.inputs[nameToInputIndex(name)] | ||
| } | ||
|
|
||
| //In the distance, someone shouting YAGNI |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's me, isn't it?
The function is a bit less safe than I originally intended, so I'm moving it to be internal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (2)
src/core/graph/widgets/dynamicWidgets.ts (2)
373-373: Guard againstnamesarray underflow.When
namesis provided butordinal >= names.length, the expressionnames ? names[ordinal] : (prefix ?? '') + ordinalwill yieldundefined, resulting in nameless inputs. Use optional chaining to fall back to the prefix:- name: names ? names[ordinal] : (prefix ?? '') + ordinal, + name: names?.[ordinal] ?? (prefix ?? '') + ordinal,Based on past review comments.
448-452: Enforceminconstraint when removing trailing empty groups.The current logic can violate the
minconstraint when shrinking groups. Add a length check before removing the last group:if ( trackedInputs.at(-2) && - !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) + !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) && + trackedInputs.length - 1 >= (min ?? 0) ) removeInputGroup(trackedInputs.at(-1)![0])This ensures at least
mingroups remain even after aggressive disconnects.Based on past review comments.
🧹 Nitpick comments (2)
src/core/graph/widgets/dynamicWidgets.ts (2)
206-207: Inconsistent link access pattern.Line 206 uses
node.graph.links[link_id]but the codebase generally uses the Map-basednode.graph._links.get(link_id)API (as seen in lines 189-190, 282, 442). Consider updating for consistency:- const link = node.graph.links[link_id] + const link = node.graph._links.get(link_id)
355-356: Document the single-input-per-group restriction.The restriction to "only 1 input per group" appears arbitrary. Add a comment explaining the rationale or consider removing this limitation if it's not technically necessary.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/core/graph/widgets/dynamicWidgets.ts(6 hunks)src/lib/litegraph/src/LGraphNode.ts(1 hunks)src/schemas/nodeDefSchema.ts(2 hunks)src/utils/typeGuardUtil.ts(1 hunks)tests-ui/tests/widgets/dynamicCombo.test.ts(4 hunks)
🧰 Additional context used
📓 Path-based instructions (15)
**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json
Files:
tests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Use es-toolkit for utility functions
Files:
tests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use TypeScript for type safety
**/*.{ts,tsx}: Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
tests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (.cursorrules)
Implement proper error handling in components and services
**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in.prettierrc
Organize imports by sorting and grouping by plugin, and runpnpm formatbefore committing
Files:
tests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
tests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,vue}: Useconst settingStore = useSettingStore()andsettingStore.get('Comfy.SomeSetting')to retrieve settings in TypeScript/Vue files
Useawait settingStore.set('Comfy.SomeSetting', newValue)to update settings in TypeScript/Vue files
Check server capabilities usingapi.serverSupportsFeature('feature_name')before using enhanced features
Useapi.getServerFeature('config_name', defaultValue)to retrieve server feature configurationEnforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates
Files:
tests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
UsedefaultsByInstallVersionproperty for gradual feature rollout based on version in settings configuration
Files:
tests-ui/tests/widgets/dynamicCombo.test.tssrc/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)
tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks
Files:
tests-ui/tests/widgets/dynamicCombo.test.ts
**/*.{test,spec}.{ts,tsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Unit and component tests should be located in
tests-ui/or co-located with components assrc/components/**/*.{test,spec}.ts; E2E tests should be inbrowser_tests/
Files:
tests-ui/tests/widgets/dynamicCombo.test.ts
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/core/graph/widgets/dynamicWidgets.tssrc/utils/typeGuardUtil.tssrc/lib/litegraph/src/LGraphNode.tssrc/schemas/nodeDefSchema.ts
src/lib/litegraph/**/*.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
src/lib/litegraph/**/*.{js,ts,jsx,tsx}: Run ESLint instead of manually figuring out whitespace fixes or other trivial style concerns using thepnpm lint:fixcommand
Take advantage ofTypedArraysubarraywhen appropriate
Thesizeandposproperties ofRectangleshare the same array buffer (subarray); they may be used to set the rectangle's size and position
Prefer single lineifsyntax over adding curly braces, when the statement has a very concise expression and concise, single line statement
Do not replace&&=or||=with=when there is no reason to do so. If you do find a reason to remove either&&=or||=, leave a comment explaining why the removal occurred
When writing methods, prefer returning idiomatic JavaScriptundefinedovernull
Files:
src/lib/litegraph/src/LGraphNode.ts
src/lib/litegraph/**/*.{ts,tsx}
📄 CodeRabbit inference engine (src/lib/litegraph/CLAUDE.md)
Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code
Files:
src/lib/litegraph/src/LGraphNode.ts
🧠 Learnings (12)
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.tssrc/lib/litegraph/src/LGraphNode.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : When writing tests for subgraph-related code, always import from the barrel export at `@/lib/litegraph/src/litegraph` to avoid circular dependency issues
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{js,ts,jsx,tsx} : When adding features, always write vitest unit tests using cursor rules in @.cursor
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Use Vitest (with happy-dom) for unit and component tests, and Playwright for E2E tests
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`
Applied to files:
tests-ui/tests/widgets/dynamicCombo.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{js,ts,jsx,tsx} : Do not replace `&&=` or `||=` with `=` when there is no reason to do so. If you do find a reason to remove either `&&=` or `||=`, leave a comment explaining why the removal occurred
Applied to files:
src/lib/litegraph/src/LGraphNode.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{ts,tsx} : Type assertions are an absolute last resort. In almost all cases, they are a crutch that leads to brittle code
Applied to files:
src/lib/litegraph/src/LGraphNode.ts
🧬 Code graph analysis (2)
tests-ui/tests/widgets/dynamicCombo.test.ts (1)
src/schemas/nodeDef/migration.ts (1)
transformInputSpecV1ToV2(96-137)
src/core/graph/widgets/dynamicWidgets.ts (5)
src/lib/litegraph/src/LGraphNode.ts (4)
LGraphNode(209-211)LGraphNode(221-4155)LGraphNode(729-737)LGraphNode(739-745)src/lib/litegraph/src/litegraph.ts (1)
LiteGraph(17-17)src/scripts/app.ts (1)
app(1708-1708)src/utils/typeGuardUtil.ts (1)
isStrings(64-66)src/composables/functional/useChainCallback.ts (1)
useChainCallback(24-35)
🪛 ESLint
tests-ui/tests/widgets/dynamicCombo.test.ts
[error] 4-4: Unable to resolve path to module '@/lib/litegraph/src/litegraph'.
(import-x/no-unresolved)
src/core/graph/widgets/dynamicWidgets.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/KqhvWipOIa'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at ExportMap.get (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/export-map.js:88:22)
at processBodyStatement (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:9:31)
at Program (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:100:21)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/namespace)
[error] 1-1: Resolve error: EACCES: permission denied, open '/lcXnuqMUkA'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-unresolved.js:31:34)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/no-unresolved)
[error] 1-1: Resolve error: EACCES: permission denied, open '/MDdqIeYIvE'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at importType (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/import-type.js:126:63)
at checkImportForRelativePackage (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:15:38)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:59:40
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/no-relative-packages)
[error] 1-1: Unable to resolve path to module 'es-toolkit'.
(import-x/no-unresolved)
[error] 3-3: Unable to resolve path to module '@/composables/functional/useChainCallback'.
(import-x/no-unresolved)
[error] 4-4: Unable to resolve path to module '@/lib/litegraph/src/types/globalEnums'.
(import-x/no-unresolved)
[error] 11-11: Unable to resolve path to module '@/lib/litegraph/src/litegraph'.
(import-x/no-unresolved)
[error] 13-13: Unable to resolve path to module '@/schemas/nodeDef/migration'.
(import-x/no-unresolved)
[error] 19-19: Unable to resolve path to module '@/schemas/nodeDefSchema'.
(import-x/no-unresolved)
[error] 20-20: Unable to resolve path to module '@/services/litegraphService'.
(import-x/no-unresolved)
[error] 21-21: Unable to resolve path to module '@/scripts/app'.
(import-x/no-unresolved)
[error] 23-23: Unable to resolve path to module '@/utils/typeGuardUtil'.
(import-x/no-unresolved)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: test
- GitHub Check: setup
- GitHub Check: lint-and-format
- GitHub Check: collect
🔇 Additional comments (7)
src/lib/litegraph/src/LGraphNode.ts (1)
416-416: LGTM! Field addition supports dynamic match-type behavior.The
comfyMatchTypefield is properly typed and optional, enabling dynamic input type management for match-type inputs. The field structure (nested Records) allows tracking match types across multiple template groups and their associated inputs.src/utils/typeGuardUtil.ts (1)
64-66: LGTM! Type guard is correctly implemented.The
isStringsguard properly validates that all elements in an array are strings usingArray.every()with atypeofcheck. The return type correctly uses a type predicate to narrow the type tostring[].tests-ui/tests/widgets/dynamicCombo.test.ts (2)
15-17: Good test helper for async operations.The
nextTickhelper usingrequestAnimationFrameis appropriate for waiting on animations and layout updates that occur after connection changes.
110-178: Comprehensive test coverage for Autogrow functionality.The test suite thoroughly covers:
- Naming strategies (prefix-based and explicit names)
- Min/max input constraints
- Growth behavior when adding connections
- Reduction behavior when removing connections
This provides good confidence in the autogrow implementation.
src/schemas/nodeDefSchema.ts (1)
228-238: Well-structured schema for Autogrow options.The
zAutogrowOptionsschema properly captures all autogrow configuration:
template.input: The input spec to replicatetemplate.names: Optional explicit names for inputstemplate.min/max: Constraints on input counttemplate.prefix: Prefix for auto-generated namesThe schema extends
zBaseInputOptionsto inherit common input properties.src/core/graph/widgets/dynamicWidgets.ts (2)
171-179: Good dispatcher pattern for dynamic inputs.The
applyDynamicInputsfunction provides a clean extensibility point for registering new dynamic input types. The registry approach allows other modules to add handlers without modifying this file.
225-237: Type combination logic is sound.The
combineTypesfunction correctly:
- Uses the
isStringstype guard to ensure all types are strings- Removes wildcards before computing intersection
- Returns wildcard if only wildcards present
- Returns
undefinedfor incompatible types
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/core/graph/widgets/dynamicWidgets.ts (1)
75-140: FixstartingInputLengthadjustment so newly added dynamic inputs aren’t dropped or left behind.When removing old dynamic inputs,
startingInputLengthis only decremented for removals withinputIndex < initialInputIndex. If there are old dynamic inputs between the widget’s input and the original array end, those removals won’t adjuststartingInputLength, sospliceInputs(node, startingInputLength)can capture only a suffix of the newly added inputs (leaving some “new” inputs in-place and mis-ordering the group).You want
startingInputLengthto keep pointing at the first newly added input after all removals, so it should be adjusted whenever a removal happens before the currentstartingInputLength, not based oninitialInputIndex.Suggested fix:
- const initialInputIndex = - node.inputs.findIndex((i) => i.name === widget.name) + 1 - let startingInputLength = node.inputs.length + let startingInputLength = node.inputs.length @@ - for (const input of Object.values(inputsToRemove)) { - const inputIndex = node.inputs.findIndex((inp) => inp === input) - if (inputIndex === -1) continue - if (inputIndex < initialInputIndex) startingInputLength-- - node.removeInput(inputIndex) - } + for (const input of Object.values(inputsToRemove)) { + const inputIndex = node.inputs.findIndex((inp) => inp === input) + if (inputIndex === -1) continue + if (inputIndex < startingInputLength) startingInputLength-- + node.removeInput(inputIndex) + }This keeps the slice boundary aligned with the “new inputs” region regardless of where old inputs were removed.
♻️ Duplicate comments (2)
src/core/graph/widgets/dynamicWidgets.ts (2)
369-375: Guard autogrow group naming against running pastnames.length.When
namesis provided but fewer than the number of autogrow groups,names[ordinal]becomesundefinedand you end up creating inputs withname: undefined, which can break lookups and widget association.You can keep the current behavior when
names[ordinal]exists while safely falling back to the prefix-based name otherwise:- name: names - ? names[ordinal] - : ((inputsV2.length == 1 ? prefix : input.name) ?? '') + ordinal, + name: + names?.[ordinal] ?? + ((inputsV2.length == 1 ? prefix : input.name) ?? '') + ordinal,This aligns with the intent and ensures every autogrow input gets a defined name.
439-471: Honor autogrowminwhen trimming trailing empty groups.The final removal step only checks that the second-to-last group is empty:
if ( trackedInputs.at(-2) && !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) ) removeInputGroup(trackedInputs.at(-1)![0])With
min > 1, you can get belowminby disconnecting until trailing groups are empty, since this condition doesn’t enforce the minimum count.You can keep the single-trailing-empty-group behavior while respecting
minby checking the length before removing:- if ( - trackedInputs.at(-2) && - !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) - ) - removeInputGroup(trackedInputs.at(-1)![0]) + if ( + trackedInputs.at(-2) && + !trackedInputs.at(-2)?.some((name) => !!nameToInput(name).link) && + trackedInputs.length - 1 >= (min ?? 0) + ) + removeInputGroup(trackedInputs.at(-1)![0])This ensures you never shrink below the configured minimum number of autogrow groups.
🧹 Nitpick comments (1)
src/core/graph/widgets/dynamicWidgets.ts (1)
249-313: Minor clarity nit: preferthis.inputsover closed-overnodeinsidewithComfyMatchTypecallback.Inside the chained
onConnectionsChangehandler you mixthis.*and the outernodevariable:const groupInputs: INodeInputSlot[] = node.inputs.filter( (inp) => inp.name in matchGroup )Since the callback is explicitly typed with
this: MatchTypeNode, usingthis.inputshere would avoid any risk of accidentally capturing the wrong node and makes the intent clearer:- const groupInputs: INodeInputSlot[] = node.inputs.filter( + const groupInputs: INodeInputSlot[] = this.inputs.filter( (inp) => inp.name in matchGroup )Behavior should remain identical but the method reads more self-contained.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/core/graph/widgets/dynamicWidgets.ts(6 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Use es-toolkit for utility functions
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
Use TypeScript for type safety
**/*.{ts,tsx}: Never useanytype - use proper TypeScript types
Never useas anytype assertions - fix the underlying type issue
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (.cursorrules)
Implement proper error handling in components and services
**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in.prettierrc
Organize imports by sorting and grouping by plugin, and runpnpm formatbefore committing
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{vue,ts}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.ts
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use camelCase for variable and setting names in TypeScript/Vue files
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,vue}: Useconst settingStore = useSettingStore()andsettingStore.get('Comfy.SomeSetting')to retrieve settings in TypeScript/Vue files
Useawait settingStore.set('Comfy.SomeSetting', newValue)to update settings in TypeScript/Vue files
Check server capabilities usingapi.serverSupportsFeature('feature_name')before using enhanced features
Useapi.getServerFeature('config_name', defaultValue)to retrieve server feature configurationEnforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates
Files:
src/core/graph/widgets/dynamicWidgets.ts
**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
UsedefaultsByInstallVersionproperty for gradual feature rollout based on version in settings configuration
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (src/CLAUDE.md)
src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase
Files:
src/core/graph/widgets/dynamicWidgets.ts
src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (src/CLAUDE.md)
Follow Vue 3 composition API style guide
Files:
src/core/graph/widgets/dynamicWidgets.ts
🪛 ESLint
src/core/graph/widgets/dynamicWidgets.ts
[error] 1-1: Resolve error: EACCES: permission denied, open '/VhYuGTSGpq'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at ExportMap.get (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/export-map.js:88:22)
at processBodyStatement (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:9:31)
at Program (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/namespace.js:100:21)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/namespace)
[error] 1-1: Resolve error: EACCES: permission denied, open '/IikaiRKUtI'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-unresolved.js:31:34)
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/no-unresolved)
[error] 1-1: Resolve error: EACCES: permission denied, open '/xiPHnNnnEn'
at Object.writeFileSync (node:fs:2409:20)
at l (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:13670)
at createFilesMatcher (file:///home/jailuser/git/node_modules/.pnpm/get-tsconfig@4.10.1/node_modules/get-tsconfig/dist/index.mjs:7:14422)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:70:65)
at Object.resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-import-resolver-typescript@4.4.4_eslint-plugin-import-x@4.16.1_@typescript-eslin_da4796079dab5a32abf73f9910d12370/node_modules/eslint-import-resolver-typescript/lib/index.js:147:20)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:69
at setRuleContext (/home/jailuser/git/node_modules/.pnpm/eslint-import-context@0.1.9_unrs-resolver@1.11.1/node_modules/eslint-import-context/lib/index.js:23:20)
at fullResolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:170:30)
at relative (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:215:12)
at resolve (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/resolve.js:220:16)
at importType (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/import-type.js:126:63)
at checkImportForRelativePackage (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:15:38)
at file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/rules/no-relative-packages.js:59:40
at checkSourceValue (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:14:9)
at checkSource (file:///home/jailuser/git/node_modules/.pnpm/eslint-plugin-import-x@4.16.1_@typescript-eslint+utils@8.44.0_eslint@9.35.0_jiti@2.5.1__d4b6b79e6f12f59d34d55ebbf27dc73f/node_modules/eslint-plugin-import-x/lib/utils/module-visitor.js:17:9)
at ruleErrorHandler (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1173:33)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:46
at Array.forEach ()
at SourceCodeVisitor.callSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-visitor.js:76:30)
at /home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:291:18
at Array.forEach ()
at SourceCodeTraverser.traverseSync (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/source-code-traverser.js:290:10)
at runRules (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1214:12)
at #flatVerifyWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2101:4)
at Linter._verifyWithFlatConfigArrayAndWithoutProcessors (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2189:43)
at Linter._verifyWithFlatConfigArray (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2292:15)
at Linter.verify (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:1677:10)
at Linter.verifyAndFix (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/linter/linter.js:2557:20)
at verifyText (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1179:45)
at readAndVerifyFile (/home/jailuser/git/node_modules/.pnpm/eslint@9.35.0_jiti@2.5.1/node_modules/eslint/lib/eslint/eslint-helpers.js:1320:10)
(import-x/no-relative-packages)
[error] 1-1: Unable to resolve path to module 'es-toolkit'.
(import-x/no-unresolved)
[error] 3-3: Unable to resolve path to module '@/composables/functional/useChainCallback'.
(import-x/no-unresolved)
[error] 4-4: Unable to resolve path to module '@/lib/litegraph/src/types/globalEnums'.
(import-x/no-unresolved)
[error] 11-11: Unable to resolve path to module '@/lib/litegraph/src/litegraph'.
(import-x/no-unresolved)
[error] 13-13: Unable to resolve path to module '@/schemas/nodeDef/migration'.
(import-x/no-unresolved)
[error] 19-19: Unable to resolve path to module '@/schemas/nodeDefSchema'.
(import-x/no-unresolved)
[error] 20-20: Unable to resolve path to module '@/services/litegraphService'.
(import-x/no-unresolved)
[error] 21-21: Unable to resolve path to module '@/scripts/app'.
(import-x/no-unresolved)
[error] 23-23: Unable to resolve path to module '@/utils/typeGuardUtil'.
(import-x/no-unresolved)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: test
- GitHub Check: lint-and-format
- GitHub Check: setup
- GitHub Check: collect
🔇 Additional comments (8)
src/core/graph/widgets/dynamicWidgets.ts (8)
163-179: Dispatcher for dynamic inputs looks good and keeps node wiring concerns localized.The
dynamicInputsmap plusapplyDynamicInputsboolean-returning dispatcher is a clean way to centralize dynamic behaviors and makes it straightforward to add more types later. The TODO about centralizing validation here also feels like the right next step but isn’t blocking.
195-223: Output type update + link pruning logic looks sound.
changeOutputTypecorrectly no-ops when the type is unchanged, updates the slot type, then walks outbound links to drop incompatible connections and notifyonConnectionsChangeon the input side. This should play nicely with both match-type recomputation and graph consistency.
225-247:combineTypes/intersectionhelpers are clear and handle wildcards as expected.The
isStringsguard, stripping of'*'viawithout, and intersection-based combination give predictable behavior for multi-type strings; returningundefinedwhen there is no overlap is a good signal for “invalid connection”. The set-based counting inintersectionalso avoids duplicate inflation.
315-336: Match-type application wiring is straightforward and matches the recomputation path.
applyMatchTypecleanly extractsallowed_types/template_id, adds the typed input, initializescomfyMatchType, and then forces a recompute withonConnectionsChangeviarequestAnimationFrame. This should ensure outputs are updated once the node is fully wired.
368-403: Autogrow group creation / shim-widget handling looks good.
addInputGroupcorrectly clones the base specs, applies the group ordinal, inserts a shim widget when needed, and splices the new inputs at the requested index while tracking group names intrackedInputs. The canvas dirtying after each addition keeps the UI in sync with structural changes.
405-420: Group removal logic is consistent and cleans up widgets + node size.
removeInputGroupproperly finds the group, removes each input viaspliceInputs, drops associated widgets by name, trimstrackedInputs, recomputes node height, and marks the canvas dirty. This is a nice mirror ofaddInputGroup.
422-438: Connection-based growth logic for autogrow looks correct.
inputConnectedonly grows when connecting into the last group and the number of groups is still belowmax(ornames.lengthfallback), then inserts the new group immediately after the last input in that group. This matches the intended “append-on-last-connect” UX.
473-504: Nice handling of connection swaps to avoid spurious grow/shrink events.Wrapping
onConnectInputto trackpendingConnection, plus theswappingConnectionflag inonConnectionsChange, cleanly distinguishes a true disconnect from a slot-to-slot swap. That should prevent unnecessary autogrow shrink/expand cycles during drag operations.
| function spliceInputs( | ||
| node: LGraphNode, | ||
| startIndex: number, | ||
| deleteCount = -1, | ||
| ...toAdd: INodeInputSlot[] | ||
| ): INodeInputSlot[] { | ||
| if (deleteCount < 0) return node.inputs.splice(startIndex) | ||
| const ret = node.inputs.splice(startIndex, deleteCount, ...toAdd) | ||
| node.inputs.slice(startIndex).forEach((input, index) => { | ||
| const link = input.link && node.graph?.links?.get(input.link) | ||
| if (link) link.target_slot = startIndex + index | ||
| }) | ||
| return ret | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use consistent link lookup in spliceInputs to avoid potential runtime errors.
Here you call node.graph?.links?.get(input.link), but elsewhere in this file (changeOutputType, withComfyMatchType) links are accessed with index syntax (node.graph.links[link_id]). If links is not actually a Map, .get will be undefined and this call can blow up; even if links is a Map, the mixed access patterns are confusing.
You can align this with the rest of the file and keep the logic simpler:
const ret = node.inputs.splice(startIndex, deleteCount, ...toAdd)
- node.inputs.slice(startIndex).forEach((input, index) => {
- const link = input.link && node.graph?.links?.get(input.link)
- if (link) link.target_slot = startIndex + index
- })
+ node.inputs.slice(startIndex).forEach((input, index) => {
+ if (!input.link || !node.graph) return
+ const link = node.graph.links[input.link]
+ if (link) link.target_slot = startIndex + index
+ })
return retThis matches the rest of the litegraph usage and avoids relying on a .get that may not exist.
🤖 Prompt for AI Agents
In src/core/graph/widgets/dynamicWidgets.ts around lines 180 to 193, replace the
inconsistent Map-style lookup node.graph?.links?.get(input.link) with the same
array/index access used elsewhere (node.graph.links[linkId]) and add a defensive
null/undefined check: compute const linkId = input.link; const link =
node.graph?.links && linkId != null ? node.graph.links[linkId] : undefined; then
only update link.target_slot when link exists; also handle the deleteCount < 0
branch similarly if it iterates inputs, ensuring no use of .get anywhere in this
file for links so access is consistent and safe.
Also fixes connections to widget inputs created by a dynamic combo breaking on reload.
Performs some refactoring to group the prior dynamic inputs code.
See also, the overarching frontend PR: comfyanonymous/ComfyUI#10832
┆Issue is synchronized with this Notion page by Unito