Skip to content

Conversation

@AustinMroz
Copy link
Collaborator

@AustinMroz AustinMroz commented Nov 22, 2025

autogrow-optional_00002

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

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)
@coderabbitai
Copy link

coderabbitai bot commented Nov 22, 2025

📝 Walkthrough

Walkthrough

Moves 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

Cohort / File(s) Summary
Core dynamic widgets enhancement
src/core/graph/widgets/dynamicWidgets.ts
Adds applyDynamicInputs dispatcher and dynamicInputs map; implements applyMatchType, applyAutogrow, changeOutputType, combineTypes, intersection, isStrings; rewrites dynamicComboWidget/autogrow behavior for inserting/removing/relinking inputs and propagating types.
Extension removal
src/extensions/core/index.ts, src/extensions/core/matchType.ts
Removes ./matchType import from index.ts and deletes matchType.ts (logic migrated into dynamicWidgets).
Schema updates
src/schemas/nodeDefSchema.ts
Removes zWidgetTemplate and template from zBaseInputOptions; exports zComfyInputsSpec; adds exported zAutogrowOptions; updates zDynamicComboInputSpec to extend zBaseInputOptions.
Service integration
src/services/litegraphService.ts
Imports applyDynamicInputs and skips default input socket creation when applyDynamicInputs(node, inputSpec) returns truthy.
Node runtime shape changes
src/lib/litegraph/src/LGraphNode.ts
Adds public comfyMatchType?: Record<string, Record<string, string>>; removes spliceInputs method.
Type guard util
src/utils/typeGuardUtil.ts
Adds exported isStrings(types: unknown[]): types is string[] type guard.
Tests updated
tests-ui/tests/widgets/dynamicCombo.test.ts
Adds LGraph import, test helpers (nextTick, addAutogrow, connectInput), and new Autogrow tests covering naming, min/max, growth, and shrink behavior.

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)
Loading
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch austin/growable-inputs

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Nov 22, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 11/26/2025, 02:48:19 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Nov 22, 2025

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 11/26/2025, 02:56:45 AM UTC

📈 Summary

  • Total Tests: 497
  • Passed: 486 ✅
  • Failed: 0
  • Flaky: 2 ⚠️
  • Skipped: 9 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 477 / ❌ 0 / ⚠️ 2 / ⏭️ 9
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 6 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@github-actions
Copy link

github-actions bot commented Nov 22, 2025

Bundle Size Report

Summary

  • Raw size: 17 MB baseline 17 MB — 🔴 +7.47 kB
  • Gzip: 3.37 MB baseline 3.36 MB — 🔴 +1.62 kB
  • Brotli: 2.58 MB baseline 2.58 MB — 🔴 +1.46 kB
  • Bundles: 93 current • 93 baseline • 52 added / 52 removed

Category Glance
App Entry Points 🔴 +7.47 kB (3.19 MB) · Vendor & Third-Party ⚪ 0 B (8.56 MB) · Other ⚪ 0 B (3.84 MB) · Graph Workspace ⚪ 0 B (944 kB) · Panels & Settings ⚪ 0 B (298 kB) · UI Components ⚪ 0 B (139 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.19 MB (baseline 3.18 MB) • 🔴 +7.47 kB

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-DJSyl8b-.js (new) 2.96 MB 🔴 +2.96 MB 🔴 +617 kB 🔴 +469 kB
assets/index-Bva2XNlb.js (removed) 2.95 MB 🟢 -2.95 MB 🟢 -614 kB 🟢 -466 kB
assets/index-DVIru41u.js (removed) 227 kB 🟢 -227 kB 🟢 -48.6 kB 🟢 -40 kB
assets/index-CY2qkevg.js (new) 222 kB 🔴 +222 kB 🔴 +47.3 kB 🔴 +39 kB
assets/index-CeNZtuzl.js (new) 345 B 🔴 +345 B 🔴 +244 B 🔴 +229 B
assets/index-rcIvArQd.js (removed) 345 B 🟢 -345 B 🟢 -244 B 🟢 -234 B

Status: 3 added / 3 removed

Graph Workspace — 944 kB (baseline 944 kB) • ⚪ 0 B

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-CASZv6KL.js (new) 944 kB 🔴 +944 kB 🔴 +183 kB 🔴 +140 kB
assets/GraphView-CIFWWpg0.js (removed) 944 kB 🟢 -944 kB 🟢 -183 kB 🟢 -140 kB

Status: 1 added / 1 removed

Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-Vd6wUIUw.js (removed) 6.54 kB 🟢 -6.54 kB 🟢 -2.14 kB 🟢 -1.9 kB
assets/UserSelectView-XPBqKTFs.js (new) 6.54 kB 🔴 +6.54 kB 🔴 +2.14 kB 🔴 +1.9 kB

Status: 1 added / 1 removed

Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CreditsPanel-CmGgzMrF.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.15 kB 🟢 -4.5 kB
assets/CreditsPanel-DtbmWM3p.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.15 kB 🔴 +4.5 kB
assets/KeybindingPanel-BNQ1cZoX.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.01 kB
assets/KeybindingPanel-YBiNIWzt.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.01 kB
assets/ExtensionPanel-BJTc9HXI.js (removed) 10.4 kB 🟢 -10.4 kB 🟢 -2.48 kB 🟢 -2.17 kB
assets/ExtensionPanel-Cl9YUJ7_.js (new) 10.4 kB 🔴 +10.4 kB 🔴 +2.48 kB 🔴 +2.17 kB
assets/AboutPanel-DiynXmzI.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/AboutPanel-EIeUCqS4.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/ServerConfigPanel-BLu1jkij.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -1.83 kB 🟢 -1.63 kB
assets/ServerConfigPanel-Bx5Pn034.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +1.83 kB 🔴 +1.62 kB
assets/UserPanel-Bf8YuikC.js (new) 6.23 kB 🔴 +6.23 kB 🔴 +1.72 kB 🔴 +1.51 kB
assets/UserPanel-DHuFxZNj.js (removed) 6.23 kB 🟢 -6.23 kB 🟢 -1.72 kB 🟢 -1.51 kB
assets/settings-BXTtSH4O.js 33.3 kB 33.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C9Pzn-NG.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CCy2fA_h.js 27.3 kB 27.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CQpqEFfl.js 26.6 kB 26.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DHcnxypw.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DhFTK9fY.js 25.1 kB 25.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DlT4t_ui.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DRgSrIdD.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-tjkeqiZq.js 21.1 kB 21.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

UI Components — 139 kB (baseline 139 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-COK52EGt.js (removed) 53.9 kB 🟢 -53.9 kB 🟢 -8.52 kB 🟢 -7.31 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-DRgPAVBA.js (new) 53.9 kB 🔴 +53.9 kB 🔴 +8.52 kB 🔴 +7.31 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-BBbrep_I.js (new) 46.9 kB 🔴 +46.9 kB 🔴 +10.1 kB 🔴 +8.76 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-DnCXauHY.js (removed) 46.9 kB 🟢 -46.9 kB 🟢 -10.1 kB 🟢 -8.77 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-BRbjRJEG.js (new) 12.8 kB 🔴 +12.8 kB 🔴 +3.35 kB 🔴 +2.98 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-Cgq5tpmF.js (removed) 12.8 kB 🟢 -12.8 kB 🟢 -3.35 kB 🟢 -2.97 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-BWnN2Yqm.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.97 kB 🔴 +2.6 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-DNzEEbAp.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.97 kB 🟢 -2.6 kB
assets/ComfyQueueButton-BXdg5EO9.js (new) 7.73 kB 🔴 +7.73 kB 🔴 +2.2 kB 🔴 +1.95 kB
assets/ComfyQueueButton-UUcIeo5m.js (removed) 7.73 kB 🟢 -7.73 kB 🟢 -2.2 kB 🟢 -1.95 kB
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-BX9pTU6E.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +827 B 🔴 +715 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-HMgZbuNY.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -826 B 🟢 -723 B
assets/WidgetButton-0Kc6B4DO.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -928 B 🟢 -816 B
assets/WidgetButton-j9A6Sc0i.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +927 B 🔴 +814 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-B4qnwhJi.js (removed) 1.34 kB 🟢 -1.34 kB 🟢 -688 B 🟢 -597 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-BUMJJ4or.js (new) 1.34 kB 🔴 +1.34 kB 🔴 +686 B 🔴 +596 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-BC86zkxe.js (removed) 897 B 🟢 -897 B 🟢 -503 B 🟢 -470 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-D3fS9V2p.js (new) 897 B 🔴 +897 B 🔴 +503 B 🔴 +438 B

Status: 9 added / 9 removed

Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-BSDGUMm1.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/keybindingService-BuCTb6XE.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.84 kB 🟢 -1.58 kB
assets/serverConfigStore-DWh54pi4.js (new) 2.83 kB 🔴 +2.83 kB 🔴 +906 B 🔴 +789 B
assets/serverConfigStore-NS6ibDz2.js (removed) 2.83 kB 🟢 -2.83 kB 🟢 -909 B 🟢 -794 B
assets/audioService-CE7SBuQO.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +960 B 🔴 +823 B
assets/audioService-wr2GTVOv.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -960 B 🟢 -824 B

Status: 3 added / 3 removed

Utilities & Hooks — 2.94 kB (baseline 2.94 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-B-Y9eDiS.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +652 B 🔴 +553 B
assets/audioUtils-CwDS4LEP.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -652 B 🟢 -544 B
assets/mathUtil-CTARWQ-l.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-CXKCRJ-m.js 460 B 460 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 1 added / 1 removed

Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-other-BsfRAqhs.js (new) 3.98 MB 🔴 +3.98 MB 🔴 +843 kB 🔴 +673 kB
assets/vendor-other-BUi7FCLE.js (removed) 3.98 MB 🟢 -3.98 MB 🟢 -843 kB 🟢 -673 kB
assets/vendor-primevue-CnO5TRm9.js (new) 1.96 MB 🔴 +1.96 MB 🔴 +336 kB 🔴 +202 kB
assets/vendor-primevue-DTsA3ueY.js (removed) 1.96 MB 🟢 -1.96 MB 🟢 -336 kB 🟢 -202 kB
assets/vendor-chart-Bc7F9itp.js (removed) 452 kB 🟢 -452 kB 🟢 -99.1 kB 🟢 -81 kB
assets/vendor-chart-CQKyEgNu.js (new) 452 kB 🔴 +452 kB 🔴 +99.1 kB 🔴 +81 kB
assets/vendor-tiptap-CaFtSsrn.js (removed) 232 kB 🟢 -232 kB 🟢 -45.7 kB 🟢 -37.7 kB
assets/vendor-tiptap-Dgg2WreI.js (new) 232 kB 🔴 +232 kB 🔴 +45.7 kB 🔴 +37.7 kB
assets/vendor-vue-DWqvgxaj.js (new) 160 kB 🔴 +160 kB 🔴 +37.3 kB 🔴 +31.6 kB
assets/vendor-vue-xOQVyCMJ.js (removed) 160 kB 🟢 -160 kB 🟢 -37.3 kB 🟢 -31.5 kB
assets/vendor-three-aR6ntw5X.js 1.37 MB 1.37 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-BZLod3g9.js 407 kB 407 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 5 added / 5 removed

Other — 3.84 MB (baseline 3.84 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WidgetRecordAudio-B1DlNSxN.js (removed) 20.5 kB 🟢 -20.5 kB 🟢 -5.26 kB 🟢 -4.65 kB
assets/WidgetRecordAudio-BPY0zVqX.js (new) 20.5 kB 🔴 +20.5 kB 🔴 +5.25 kB 🔴 +4.65 kB
assets/AudioPreviewPlayer-BLipS-SD.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.07 kB
assets/AudioPreviewPlayer-BODIR83i.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.07 kB
assets/WidgetGalleria-BazL8ilZ.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.45 kB 🟢 -1.3 kB
assets/WidgetGalleria-vOWRxIrF.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.44 kB 🔴 +1.31 kB
assets/WidgetColorPicker-BBS-gX_3.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetColorPicker-Cf-gaLfg.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetMarkdown-B7bJIN89.js (removed) 3.16 kB 🟢 -3.16 kB 🟢 -1.32 kB 🟢 -1.15 kB
assets/WidgetMarkdown-D0bJUu2y.js (new) 3.16 kB 🔴 +3.16 kB 🔴 +1.32 kB 🔴 +1.15 kB
assets/WidgetAudioUI-BJoJI0f6.js (removed) 2.82 kB 🟢 -2.82 kB 🟢 -1.12 kB 🟢 -1.01 kB
assets/WidgetAudioUI-Cag4ENN3.js (new) 2.82 kB 🔴 +2.82 kB 🔴 +1.12 kB 🔴 +1.02 kB
assets/MediaVideoTop-DggHCoLj.js (new) 2.76 kB 🔴 +2.76 kB 🔴 +1.05 kB 🔴 +900 B
assets/MediaVideoTop-P2MYHlgs.js (removed) 2.76 kB 🟢 -2.76 kB 🟢 -1.05 kB 🟢 -902 B
assets/WidgetTextarea-Bnp9dOZD.js (new) 2.54 kB 🔴 +2.54 kB 🔴 +1.04 kB 🔴 +909 B
assets/WidgetTextarea-C1eNGFDg.js (removed) 2.54 kB 🟢 -2.54 kB 🟢 -1.04 kB 🟢 -909 B
assets/WidgetChart-CS3_tu0a.js (new) 2.48 kB 🔴 +2.48 kB 🔴 +931 B 🔴 +815 B
assets/WidgetChart-DaKVD7Py.js (removed) 2.48 kB 🟢 -2.48 kB 🟢 -933 B 🟢 -815 B
assets/WidgetImageCompare-DE5-CeXh.js (removed) 2.21 kB 🟢 -2.21 kB 🟢 -749 B 🟢 -659 B
assets/WidgetImageCompare-DOrXrKrE.js (new) 2.21 kB 🔴 +2.21 kB 🔴 +748 B 🔴 +662 B
assets/WidgetInputText-CbCSRU3i.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +916 B 🔴 +854 B
assets/WidgetInputText-uvVOHOp5.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -916 B 🟢 -848 B
assets/WidgetToggleSwitch-DTgLtTw7.js (new) 1.76 kB 🔴 +1.76 kB 🔴 +834 B 🔴 +733 B
assets/WidgetToggleSwitch-DTZlYmAZ.js (removed) 1.76 kB 🟢 -1.76 kB 🟢 -834 B 🟢 -728 B
assets/MediaImageTop-BTxsJ9KT.js (removed) 1.68 kB 🟢 -1.68 kB 🟢 -813 B 🟢 -692 B
assets/MediaImageTop-BZ-1jpx_.js (new) 1.68 kB 🔴 +1.68 kB 🔴 +809 B 🔴 +685 B
assets/MediaImageBottom-DenaR-P8.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +736 B 🔴 +646 B
assets/MediaImageBottom-DvXGEX0L.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -739 B 🟢 -648 B
assets/MediaAudioBottom-DdQKTFwo.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +740 B 🔴 +656 B
assets/MediaAudioBottom-Niej3E6v.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -740 B 🟢 -656 B
assets/MediaVideoBottom-Budle4MJ.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -736 B 🟢 -652 B
assets/MediaVideoBottom-TAensfHr.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +737 B 🔴 +658 B
assets/Media3DBottom-CtMj--99.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +729 B 🔴 +647 B
assets/Media3DBottom-DpOpN_Pb.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -730 B 🟢 -648 B
assets/Media3DTop-DZ5eGX43.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +764 B 🔴 +655 B
assets/Media3DTop-wB_WWFja.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -765 B 🟢 -652 B
assets/MediaAudioTop-BREn-nJl.js (new) 1.46 kB 🔴 +1.46 kB 🔴 +737 B 🔴 +616 B
assets/MediaAudioTop-ClVHGsSJ.js (removed) 1.46 kB 🟢 -1.46 kB 🟢 -740 B 🟢 -618 B
assets/WidgetSelect-BBDyxS_J.js (new) 655 B 🔴 +655 B 🔴 +339 B 🔴 +288 B
assets/WidgetSelect-CrTUSxZI.js (removed) 655 B 🟢 -655 B 🟢 -344 B 🟢 -289 B
assets/WidgetInputNumber-CnZA-vHZ.js (removed) 595 B 🟢 -595 B 🟢 -328 B 🟢 -277 B
assets/WidgetInputNumber-DPL90pzu.js (new) 595 B 🔴 +595 B 🔴 +328 B 🔴 +276 B
assets/Load3D-91tVuccq.js (new) 424 B 🔴 +424 B 🔴 +268 B 🔴 +224 B
assets/Load3D-BWphZ693.js (removed) 424 B 🟢 -424 B 🟢 -269 B 🟢 -223 B
assets/WidgetLegacy-6NBmeiXo.js (new) 364 B 🔴 +364 B 🔴 +235 B 🔴 +194 B
assets/WidgetLegacy-DtYBJcKe.js (removed) 364 B 🟢 -364 B 🟢 -237 B 🟢 -194 B
assets/commands-_s-RvhJR.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BuUILW6P.js 13 kB 13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BV4R6fLx.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CLwPdnT6.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CWMchBmd.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DazTQhtc.js 12.9 kB 12.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DmWrOe93.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DwiH7Kr6.js 13.8 kB 13.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-mS3LCNPn.js 14.5 kB 14.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-5lOBdqcC.js 84.5 kB 84.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BOCuaVpE.js 73.4 kB 73.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-ClrEFGUz.js 72.4 kB 72.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CyNU0iQX.js 99.3 kB 99.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-D7gwLxft.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DC8o4BCt.js 86.8 kB 86.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DKiesCV4.js 94.3 kB 94.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Hq2q-OtB.js 83.6 kB 83.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-USAlAlnj.js 82 kB 82 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-_Px5dSNW.js 306 kB 306 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-7z21KPoS.js 285 kB 285 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BWKZzBPK.js 346 kB 346 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CGbgH4Yl.js 320 kB 320 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CjjjdWkV.js 313 kB 313 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CVrNtxvj.js 288 kB 288 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DLRSA0IK.js 309 kB 309 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DQV2gnwA.js 372 kB 372 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-ofqLG5vz.js 310 kB 310 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 23 added / 23 removed

@github-actions
Copy link

🔧 Auto-fixes Applied

This PR has been automatically updated to fix linting and formatting issues.

⚠️ Important: Your local branch is now behind. Run git pull before making additional changes to avoid conflicts.

Changes made:

  • ESLint auto-fixes
  • Prettier formatting

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
@AustinMroz AustinMroz force-pushed the austin/growable-inputs branch from 49f4a8c to c76b8c3 Compare November 24, 2025 19:53
@AustinMroz AustinMroz marked this pull request as ready for review November 25, 2025 01:04
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Nov 25, 2025
Copy link

@coderabbitai coderabbitai bot left a 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 the zAutogrowOptions schema.

The schema structure is clear, but documenting the purpose of each field (especially the relationship between names, prefix, min, and max) would improve maintainability.


338-348: Magic timeout value and potential timing issues.

The setTimeout(..., 50) pattern appears multiple times in this file. Consider:

  1. Extracting the magic number to a named constant to document its purpose
  2. 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 pendingConnection and swappingConnection flags 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: Use es-toolkit/compat intersection instead of custom implementation.

The custom intersection function (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

📥 Commits

Reviewing files that changed from the base of the PR and between c06a727 and f44595d.

📒 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.ts
  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/schemas/nodeDefSchema.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursorrules)

Use es-toolkit for utility functions

Files:

  • src/services/litegraphService.ts
  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/schemas/nodeDefSchema.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use TypeScript for type safety

**/*.{ts,tsx}: Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • src/services/litegraphService.ts
  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/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 run pnpm format before committing

Files:

  • src/services/litegraphService.ts
  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/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.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/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.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/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.ts
  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/schemas/nodeDefSchema.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,vue}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates

Files:

  • src/services/litegraphService.ts
  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/schemas/nodeDefSchema.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
Use defaultsByInstallVersion property for gradual feature rollout based on version in settings configuration

Files:

  • src/services/litegraphService.ts
  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/schemas/nodeDefSchema.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.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.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/schemas/nodeDefSchema.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/services/litegraphService.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/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 as src/components/**/*.{test,spec}.ts; E2E tests should be in browser_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.ts
  • tests-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.ts
  • tests-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! Exporting zComfyInputsSpec for 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 addAutogrow and connectInput helpers encapsulate common test setup patterns, making the test cases more readable. The use of transformInputSpecV1ToV2 is consistent with the existing addDynamicCombo helper.


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 applyDynamicInputs function 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:

  1. Checking if the old input exists and has a compatible type
  2. 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 that COMFY_AUTOGROW_V3 and COMFY_MATCHTYPE_V3 are registered in a handler map in src/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:

  1. If a widget constructor exists AND forceInput is not set → return (create as widget)
  2. If the first condition is false → call applyDynamicInputs which handles COMFY_AUTOGROW_V3 and COMFY_MATCHTYPE_V3 types through a handler map, not via widget constructors

Since COMFY_AUTOGROW_V3 and COMFY_MATCHTYPE_V3 are handled via the applyDynamicInputs handler map (not widget constructors), they will never be short-circuited by the first condition. The logic is sound.

@AustinMroz AustinMroz requested a review from a team as a code owner November 25, 2025 02:29
Copy link

@coderabbitai coderabbitai bot left a 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 structure

The concern is valid but applies to a specific scenario. After analyzing the code:

  1. 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 their link.target_slot values.

  2. Partial re-sync by spliceInputs: The subsequent spliceInputs calls (lines 150, 160) only re-sync target_slot for inputs from their startIndex onward. Specifically, line 160's call syncs only from inputInsertionPoint (the position after the combo widget).

  3. 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_slot values aren't updated by spliceInputs. This creates a mismatch: input.link references a link ID whose link.target_slot now points elsewhere.

  4. Confirmation from autogrow code: Lines 449–458 show the dynamicInputs function explicitly re-syncs target_slot after manipulating input.link directly, 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 mutating output.links while iterating

changeOutputType walks output.links while 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 disconnect mutates output.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 connections

The match‑type handler:

  • Builds comfyMatchType groups per template_id.
  • On connection changes, computes compatible per‑input and per‑output types via combineTypes.
  • Uses changeOutputType so invalid downstream connections get dropped when output types tighten.

This is a solid approach and nicely reuses the shared helpers.

One behavioral nit: when combineTypes returns undefined, the code throws new 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 possible

The 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 50 ms 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

📥 Commits

Reviewing files that changed from the base of the PR and between f44595d and 3882c7e.

📒 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 use any type - use proper TypeScript types
Never use as any type 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 run pnpm format before 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}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce 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
Use defaultsByInstallVersion property 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 solid

The MatchTypeNode augmentation and both zod schemas (zAutogrowOptions, zDynamicComboInputSpec) are well-typed and align with the described backend behavior (more lenient frontend min, explicit options structure). No functional issues spotted here.

Also applies to: 37-47


180-196: Dynamic input dispatcher is clean and extensible

The dynamicInputs map plus applyDynamicInputs boolean 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.

Copy link

@coderabbitai coderabbitai bot left a 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 update LLink.target_slot (graph state may become inconsistent).

When reusing existing links for new dynamic inputs, only node.inputs.at(-1)!.link is updated. The corresponding graph.links[linkId].target_slot is 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 desynchronize inputs[*].link from graph.links[*].target_slot, especially after removeInput / spliceInputs reindexing.

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 = newInputIndex

This 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: Apply useChainCallback to node.onConnectInput to 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), calling addInputSocket for each. If multiple specs have type COMFY_AUTOGROW_V3, then applyAutogrow is invoked multiple times on the same node, each replacing node.onConnectInput without proper chaining. This leaves earlier autogrow handlers' pendingConnection/swappingConnection flags unreachable in subsequent wrappers, causing disconnection-swap logic to misfire.

While onConnectionsChange is correctly chained via useChainCallback (line 481), onConnectInput uses manual replacement (line 469). Applying the same useChainCallback pattern to onConnectInput (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

📥 Commits

Reviewing files that changed from the base of the PR and between 3882c7e and d19506c.

📒 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 use any type - use proper TypeScript types
Never use as any type 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 run pnpm format before 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}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce 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
Use defaultsByInstallVersion property 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

Comment on lines +435 to +467
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])
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
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.

Copy link

@coderabbitai coderabbitai bot left a 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 names is provided but ordinal >= names.length, names[ordinal] returns undefined, 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 min when 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 setTimeout is 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 !== 1 throws). 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

📥 Commits

Reviewing files that changed from the base of the PR and between d19506c and 5606827.

📒 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 use any type - use proper TypeScript types
Never use as any type 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 run pnpm format before 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}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce 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
Use defaultsByInstallVersion property 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's without utility and proper TypeScript type guards. The intersection logic correctly computes common types across all input sets.


470-501: LGTM: Proper connection state management.

The onConnectInput and onConnectionsChange wiring correctly handles connection swapping and prevents spurious disconnection events. The use of useChainCallback to compose callbacks is clean and maintains existing behavior.

).template
const typedSpec = { ...inputSpec, type: allowed_types }
addNodeInput(node, typedSpec)
//Sorry
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are not forgiven.

Comment on lines 335 to 336
augmentedNode.comfyMatchType[template_id] ??= {}
augmentedNode.comfyMatchType[template_id][name] = allowed_types
Copy link
Contributor

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
Copy link
Contributor

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.
Copy link

@coderabbitai coderabbitai bot left a 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 against names array underflow.

When names is provided but ordinal >= names.length, the expression names ? names[ordinal] : (prefix ?? '') + ordinal will yield undefined, 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: Enforce min constraint when removing trailing empty groups.

The current logic can violate the min constraint 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 min groups 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-based node.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

📥 Commits

Reviewing files that changed from the base of the PR and between 5606827 and bbab14d.

📒 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.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/schemas/nodeDefSchema.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursorrules)

Use es-toolkit for utility functions

Files:

  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/schemas/nodeDefSchema.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use TypeScript for type safety

**/*.{ts,tsx}: Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/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 run pnpm format before committing

Files:

  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/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.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/schemas/nodeDefSchema.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,vue}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce 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.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/schemas/nodeDefSchema.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
Use defaultsByInstallVersion property for gradual feature rollout based on version in settings configuration

Files:

  • tests-ui/tests/widgets/dynamicCombo.test.ts
  • src/core/graph/widgets/dynamicWidgets.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/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 as src/components/**/*.{test,spec}.ts; E2E tests should be in browser_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.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/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.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/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.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/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.ts
  • src/utils/typeGuardUtil.ts
  • src/lib/litegraph/src/LGraphNode.ts
  • src/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 the pnpm lint:fix command
Take advantage of TypedArray subarray when appropriate
The size and pos properties of Rectangle share the same array buffer (subarray); they may be used to set the rectangle's size and position
Prefer single line if syntax 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 JavaScript undefined over null

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.ts
  • 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/**/*.{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 comfyMatchType field 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 isStrings guard properly validates that all elements in an array are strings using Array.every() with a typeof check. The return type correctly uses a type predicate to narrow the type to string[].

tests-ui/tests/widgets/dynamicCombo.test.ts (2)

15-17: Good test helper for async operations.

The nextTick helper using requestAnimationFrame is 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 zAutogrowOptions schema properly captures all autogrow configuration:

  • template.input: The input spec to replicate
  • template.names: Optional explicit names for inputs
  • template.min/max: Constraints on input count
  • template.prefix: Prefix for auto-generated names

The schema extends zBaseInputOptions to inherit common input properties.

src/core/graph/widgets/dynamicWidgets.ts (2)

171-179: Good dispatcher pattern for dynamic inputs.

The applyDynamicInputs function 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 combineTypes function correctly:

  1. Uses the isStrings type guard to ensure all types are strings
  2. Removes wildcards before computing intersection
  3. Returns wildcard if only wildcards present
  4. Returns undefined for incompatible types

Copy link

@coderabbitai coderabbitai bot left a 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: Fix startingInputLength adjustment so newly added dynamic inputs aren’t dropped or left behind.

When removing old dynamic inputs, startingInputLength is only decremented for removals with inputIndex < initialInputIndex. If there are old dynamic inputs between the widget’s input and the original array end, those removals won’t adjust startingInputLength, so spliceInputs(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 startingInputLength to keep pointing at the first newly added input after all removals, so it should be adjusted whenever a removal happens before the current startingInputLength, not based on initialInputIndex.

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 past names.length.

When names is provided but fewer than the number of autogrow groups, names[ordinal] becomes undefined and you end up creating inputs with name: 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 autogrow min when 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 below min by 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 min by 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: prefer this.inputs over closed-over node inside withComfyMatchType callback.

Inside the chained onConnectionsChange handler you mix this.* and the outer node variable:

const groupInputs: INodeInputSlot[] = node.inputs.filter(
  (inp) => inp.name in matchGroup
)

Since the callback is explicitly typed with this: MatchTypeNode, using this.inputs here 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

📥 Commits

Reviewing files that changed from the base of the PR and between bbab14d and 88e5728.

📒 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 use any type - use proper TypeScript types
Never use as any type 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 run pnpm format before 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}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce 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
Use defaultsByInstallVersion property 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 dynamicInputs map plus applyDynamicInputs boolean-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.

changeOutputType correctly no-ops when the type is unchanged, updates the slot type, then walks outbound links to drop incompatible connections and notify onConnectionsChange on the input side. This should play nicely with both match-type recomputation and graph consistency.


225-247: combineTypes / intersection helpers are clear and handle wildcards as expected.

The isStrings guard, stripping of '*' via without, and intersection-based combination give predictable behavior for multi-type strings; returning undefined when there is no overlap is a good signal for “invalid connection”. The set-based counting in intersection also avoids duplicate inflation.


315-336: Match-type application wiring is straightforward and matches the recomputation path.

applyMatchType cleanly extracts allowed_types / template_id, adds the typed input, initializes comfyMatchType, and then forces a recompute with onConnectionsChange via requestAnimationFrame. This should ensure outputs are updated once the node is fully wired.


368-403: Autogrow group creation / shim-widget handling looks good.

addInputGroup correctly 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 in trackedInputs. 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.

removeInputGroup properly finds the group, removes each input via spliceInputs, drops associated widgets by name, trims trackedInputs, recomputes node height, and marks the canvas dirty. This is a nice mirror of addInputGroup.


422-438: Connection-based growth logic for autogrow looks correct.

inputConnected only grows when connecting into the last group and the number of groups is still below max (or names.length fallback), 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 onConnectInput to track pendingConnection, plus the swappingConnection flag in onConnectionsChange, cleanly distinguishes a true disconnect from a slot-to-slot swap. That should prevent unnecessary autogrow shrink/expand cycles during drag operations.

Comment on lines +180 to +193
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
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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 ret

This 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants