Hide the template selector when a first-time cloud user accepts a shared workflow from a share link, so the shared workflow opens without the onboarding template dialog lingering. - **What**: Added shared-workflow loader behavior to close the global template selector on accept actions (`copy-and-open` and `open-only`) while keeping cancel behavior unchanged. - **What**: Added targeted unit tests covering hide-on-accept and no-hide-on-cancel behavior in the shared workflow URL loader. Confirm that share-link accept paths now dismiss the template selector and that cancel still leaves it available. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9913-fix-hide-template-selector-after-shared-workflow-accept-3236d73d365081099c04e350d499fad2) by [Unito](https://www.unito.io) Co-authored-by: Amp <amp@ampcode.com> fix: restore native copy/paste events for image paste support (#9914) - Remove Ctrl+C and Ctrl+V keybindings from the keybinding service defaults so native browser copy/paste events fire - This restores image paste into LoadImage nodes, which broke after PR #9459 moved Ctrl+C/V into the keybinding service, which calls `event.preventDefault()` on keydown. This prevents the browser `paste` event from firing, so `usePaste` (which detects images in the clipboard) never runs. The `PasteFromClipboard` command only reads from localStorage, completely bypassing image detection. **Repro:** Copy a node → copy an image externally → try to paste the image into a LoadImage node → gets old node data from localStorage instead. Remove Ctrl+C and Ctrl+V from `CORE_KEYBINDINGS` in `defaults.ts`. The native browser events now fire as before, and `useCopy`/`usePaste` handle them correctly. Ctrl+Shift+V, Ctrl+A, Delete, and Backspace keybindings remain in the keybinding service. Fixes #9459 (regression) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9914-fix-restore-native-copy-paste-events-for-image-paste-support-3236d73d365081c7ac53f983f316e10f) by [Unito](https://www.unito.io) fix: clear stale widget slotMetadata on link disconnect (#9885) Fixes text field becoming non-editable when a previously linked input is removed from a custom node. When a widget's input was promoted to a slot, connected via a link, and then the input was removed (e.g., by updating the custom node definition), the widget retained stale `slotMetadata` with `linked: true`. This prevented the widget from being editable. In `refreshNodeSlots`, removed the `if (slotInfo)` guard so `widget.slotMetadata` is always assigned — either to valid metadata or `undefined`. This ensures stale linked state is cleared when inputs no longer match widgets. 1. Text field remains editable after promote→connect→disconnect cycle 2. Text field returns to editable state when noodle disconnected 3. No mode switching needed to restore editability - Added regression test: "clears stale slotMetadata when input no longer matches widget" - All existing tests pass (18/18 in affected file) --- **Note: This PR currently contains only the RED (failing test) commit for TDD verification. The GREEN (fix) commit will be pushed after CI confirms the test failure.** ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9885-fix-clear-stale-widget-slotMetadata-on-link-disconnect-3226d73d365081269319c027b42d9f6b) by [Unito](https://www.unito.io) fix: stabilize subgraph promoted widget identity and rendering (#9896) Fix subgraph promoted widget identity/rendering so on-node widgets stay correct through configure/hydration churn, duplicate names, and linked+independent coexistence. - **Subgraph promotion reconciliation**: stabilize linked-entry identity by subgraph slot id, preserve deterministic linked representative selection, and prune stale alias/fallback entries without dropping legitimate independent promotions. - **Promoted view resolution**: bind slot mapping by promoted view object identity (`getSlotFromWidget` / `getWidgetFromSlot`) to avoid same-name collisions. - **On-node widget rendering**: harden `NodeWidgets` identity and dedup to avoid visual aliasing, prefer visible duplicates over hidden stale entries, include type/source execution identity, and avoid collapsing transient unresolved entries. - **Mapping correctness**: update `useGraphNodeManager` promoted source mapping to resolve by input target only when the promoted view is actually bound to that input. - **Subgraph input uniqueness**: ensure empty-slot promotion creates unique input names (`seed`, `seed_1`, etc.) for same-name multi-source promotions. - **Safety fix**: guard against undefined canvas in slot-link interaction. - **Tests/fixtures**: add focused regressions for fixture path `subgraph_complex_promotion_1`, linked+independent same-name cases, duplicate-name identity mapping, dedup behavior, and input-name uniqueness. Validate behavior around transient configure/hydration states (`-1` id to concrete id), duplicate-name promotions, linked representative recovery, and that dedup never hides legitimate widgets while still removing true duplicates. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9896-fix-stabilize-subgraph-promoted-widget-identity-and-rendering-3226d73d365081c8a1e8d0a5a22e826d) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com> 1.42.5 (#9906) Patch version increment to 1.42.5 **Base branch:** `main` --------- Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com> fix: skip redundant appScalePercentage updates during zoom/pan (#9403) Add equality check before updating `appScalePercentage` reactive ref. Firefox profiler shows 586 `setElementText` markers from continuous text interpolation updates during zoom/pan. The rounded percentage value often doesn't change between events. Extract `updateAppScalePercentage()` helper with equality guard — compares new rounded value to current before assigning to the ref. Expected: eliminates ~90% of `setElementText` markers during zoom/pan ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9403-fix-skip-redundant-appScalePercentage-updates-during-zoom-pan-31a6d73d3650812db8f2d68ac73c95b0) by [Unito](https://www.unito.io) test: add browser test for textarea right-click context menu in subgraph (#9891) Add E2E test coverage for the textarea widget right-click context menu inside subgraphs. The fix was shipped in #9840 — this PR adds the missing browser test. - Loads a subgraph workflow with a CLIPTextEncode (textarea) node - Navigates into the subgraph - Right-clicks the textarea DOM element - Asserts that the ComfyUI "Promote Widget" context menu option appears - Fixes the test gap from #9840 - Notion ticket: d7a53160-e1e1-42bb-a5ac-c0c2702c629c ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9891-test-add-browser-test-for-textarea-right-click-context-menu-in-subgraph-3226d73d365081a4be51f89b5d505361) by [Unito](https://www.unito.io) feat: expand CDP perf metrics — add DOM nodes, script duration, event listeners (#9887) Expands the performance testing infrastructure to collect 4 additional CDP metrics that are already returned by `Performance.getMetrics` but were not being read. This is a zero-cost expansion — no additional CDP calls, just reading more fields from the existing response. | Metric | CDP Source | What It Detects | |---|---|---| | `domNodes` | `Nodes` | DOM node count delta — widget DOM leaks during node create/destroy | | `jsHeapTotalBytes` | `JSHeapTotalSize` | Total heap delta — combined with `heapDeltaBytes` shows GC pressure | | `scriptDurationMs` | `ScriptDuration` | JS execution time vs total task time — script vs rendering balance | | `eventListeners` | `JSEventListeners` | Listener count delta — detects listener accumulation across lifecycle | - Added 4 fields to `PerfSnapshot` interface - Added 4 fields to `PerfMeasurement` interface - Wired through `getSnapshot()` and `stopMeasuring()` - Added 4 fields to `PerfMeasurement` interface - Expanded `MetricKey` type and `REPORTED_METRICS` array with 3 new reported metrics (`domNodes`, `scriptDurationMs`, `eventListeners`) - `jsHeapTotalBytes` is collected but not in `REPORTED_METRICS` — it's used alongside `heapDeltaBytes` for GC pressure ratio analysis From a gap analysis of all ~30 CDP metrics, these were identified as highest priority for ComfyUI: - **`Nodes`** (P0): ComfyUI dynamically creates/destroys widget DOM. DOM bloat from leaked widgets is a key performance risk, especially for Vue Nodes 2.0. - **`ScriptDuration`** (P1): Separates JS execution from layout/paint. Reveals whether perf issues are script-heavy or rendering-heavy. - **`JSEventListeners`** (P1): Widget lifecycle can leak listeners across node add/remove cycles. - **`JSHeapTotalSize`** (P1): With `JSHeapUsedSize`, the ratio shows GC fragmentation pressure. The `PerfMeasurement` interface is extended (not changed). Old baseline `perf-metrics.json` files without these fields will have `undefined` values, which the report script handles gracefully (shows `—` for missing data). ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9887-feat-expand-CDP-perf-metrics-add-DOM-nodes-script-duration-event-listeners-3226d73d3650818abea1d4a441667c38) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> fix: prevent white flash when opening mask editor (#9860) - Remove hardcoded `bg-white` from mask editor canvas background div to prevent white flash on dialog open - Add a loading spinner while the mask editor initializes (image loading, canvas setup, GPU resources) - Background color is set dynamically by `setCanvasBackground()` after initialization Fixes #9852 https://github.com/user-attachments/assets/7da61e32-671b-4056-b5ec-8cb246fc7689 https://github.com/user-attachments/assets/bfdedc69-f690-42c5-8591-619623c04f55 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9860-fix-prevent-white-flash-when-opening-mask-editor-3226d73d365081de9b7ad4622438e6ed) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> fix: prevent live preview dimension flicker between frames (#9937) Fix "Calculating dimensions" text flickering during live sampling preview in Vue renderer. - **What**: Stop resetting `actualDimensions` to `null` on every `imageUrl` change. Previous dimensions are retained while the new frame loads, eliminating the flicker. Error state is still reset correctly. The watcher on `props.imageUrl` previously reset both `actualDimensions` and `imageError`. Now it only resets `imageError`, since `handleImageLoad` updates dimensions when the new frame actually loads. This means stale dimensions show briefly between frames, which is intentionally better than showing "Calculating dimensions" text. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9937-fix-prevent-live-preview-dimension-flicker-between-frames-3246d73d36508154a676e5996112354f) by [Unito](https://www.unito.io) feat: make Vue nodes (Nodes 2.0) default for new desktop installs (#9947) Makes Vue nodes (Nodes 2.0) the default renderer for new desktop app installs (version ≥1.41.0), matching the behavior already live for cloud new installs. Step 2 of the Nodes 2.0 rollout sequence: 1. ✅ Cloud new installs (≥1.41.0) — DONE 2. 👉 **Desktop app (new installs)** — this PR 3. ⬜ Local installs 4. ⬜ Remove Beta tag 5. ⬜ GTM announcement No forced migration — only changes the default for new installs. Existing users keep their setting. Rollback is a settings flip. In `coreSettings.ts`, the `defaultsByInstallVersion` for `Comfy.VueNodes.Enabled` changes from: ```typescript defaultsByInstallVersion: { '1.41.0': isCloud }, ``` to: ```typescript defaultsByInstallVersion: { '1.41.0': isCloud || isDesktop }, ``` - M2 perf target (≥52 FPS on 245-node workflow) — layer merge landed, likely met - M-DevRel migration docs (blocks Beta tag removal, not this flip) Draft PR — ceremonial, to be merged when M2 checkpoint passes. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9947-feat-make-Vue-nodes-Nodes-2-0-default-for-new-desktop-installs-3246d73d365081b280dfff932c7aa016) by [Unito](https://www.unito.io) fix: fix perf CI pipeline — z-score baselines, force-push staleness, baseline storage (#9886) Fixes three critical issues with the CI performance reporting pipeline that made perf reports useless on PRs (demonstrated by PR #9248 — deep watcher removal merged without useful perf signal). **Root cause:** PR #9305 added z-score statistical analysis code to `perf-report.ts`, but the historical data download step was placed in the wrong workflow file. The report is generated in `pr-perf-report.yaml` (a `workflow_run`-triggered job), but the historical download was in `ci-perf-report.yaml` (the test runner) — different runners, different filesystems. **Fix:** Implement `perf-data` orphan branch storage: - On push to main: save `perf-metrics.json` to `perf-data` branch with timestamped filename - On PR report: fetch last 5 baselines from `perf-data` branch into `temp/perf-history/` - Rolling window of 20 baselines, oldest pruned automatically - Same pattern used by `github-action-benchmark` (33.7k repos) **Root cause:** `cancel-in-progress: true` kills the perf test run before it uploads artifacts. The downstream report workflow only triggers on `conclusion == 'success'` — cancelled runs are ignored, so the comment from the first successful run goes stale. **Fix:** - Change `cancel-in-progress: false` — with GitHub's queue depth of 1, rapid pushes (A,B,C,D) run A and D, skipping B and C - Add SHA validation in `pr-perf-report.yaml` — before posting, check if the workflow_run's head SHA still matches the PR's current head. Skip posting stale results. - `contents: write` on CI job (needed for pushing to perf-data branch) - `actions: read` on both workflows (needed for artifact/baseline access) After merging, create the `perf-data` orphan branch: ```bash git checkout --orphan perf-data git rm -rf . echo '# Performance Baselines' > README.md mkdir -p baselines git add README.md baselines git commit -m 'Initialize perf-data branch' git push origin perf-data ``` The first 2 pushes to main after setup will build up variance data, and z-scores will start appearing in PR reports (threshold is `historical.length >= 2`). - YAML validated with `yaml.safe_load()` - `perf-report.ts` `loadHistoricalReports()` already reads from `temp/perf-history/<index>/perf-metrics.json` — no code changes needed - All new steps use `continue-on-error: true` for graceful degradation ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9886-fix-fix-perf-CI-pipeline-z-score-baselines-force-push-staleness-baseline-storage-3226d73d365081538424c7945e71f308) by [Unito](https://www.unito.io) draft: add red-green-fix skill for verified bug fix workflow (#9954) - Add a Claude Code skill (`/red-green-fix`) that enforces the red-green commit pattern for bug fixes - Ensures a failing test is committed first (red CI), then the fix is committed separately (green CI) - Gives reviewers proof that the test actually catches the bug - Includes `reference/testing-anti-patterns.md` with common mistakes contextualized to this codebase ``` .claude/skills/red-green-fix/ ├── SKILL.md # Main skill definition └── reference/ └── testing-anti-patterns.md # Anti-patterns guide ``` - [ ] Invoke `/red-green-fix <bug description>` in Claude Code and verify the two-step workflow - [ ] Confirm PR template includes red-green verification table - [ ] Review anti-patterns reference for completeness ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9954-draft-add-red-green-fix-skill-for-verified-bug-fix-workflow-3246d73d365081339a83dc09263b0f33) by [Unito](https://www.unito.io) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: GitHub Action <action@github.com> test: add large-graph perf test with 245-node workflow (backlog N5) (#9940) Adds a 245-node workflow asset and two `@perf` tests to establish a baseline for large-graph performance regressions (Tier 6 in the performance backlog). Backlog item N5: we need CI regression detection for compositor layer management, GPU texture count, and transform pane cost at 245+ nodes. This is PR1 of 2 — establishes baseline metrics on main. Future optimization PRs will show improvement deltas against this baseline. - **`large graph idle rendering`** — 120 frames idle with 245 nodes, measures style recalcs, layouts, task duration, heap delta - **`large graph pan interaction`** — middle-click pan across 245 nodes, stresses compositor layer management and transform recalculation `browser_tests/assets/large-graph-workflow.json` — 245 nodes (49 pipelines of CheckpointLoader → 2× CLIPTextEncode → KSampler + EmptyLatentImage), 294 links. Minimal structure focused on node count. - [x] `pnpm typecheck:browser` passes - [x] `pnpm lint` passes (eslint on changed file) - [x] All link references in JSON validated programmatically ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9940-test-add-large-graph-perf-test-with-245-node-workflow-backlog-N5-3246d73d365081f6b5d8ddb9a85e6ad0) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com> feat: add Ingest API codegen with Zod schema generation (#9932) - Add `packages/ingest-types/` package that auto-generates TypeScript types and Zod schemas from the Ingest service OpenAPI spec - Uses `@hey-api/openapi-ts` with built-in Zod plugin (Zod v3 compatible) - Filters out overlapping endpoints shared with the local ComfyUI Python backend - Generates **493 TypeScript types** and **256 Zod schemas** covering cloud-only endpoints - Configure knip to ignore generated files The cloud repo pushes generated types to this repo (push model, no private repo cloning). See: Comfy-Org/cloud#2858 Codegen targets are controlled by the **exclude list** in `packages/ingest-types/openapi-ts.config.ts`. Everything in the Ingest `openapi.yaml` is included **except** overlapping endpoints that also exist in the local ComfyUI Python backend: **Excluded (overlapping with ComfyUI Python):** `/prompt`, `/queue`, `/history`, `/object_info`, `/features`, `/settings`, `/system_stats`, `/interrupt`, `/upload/*`, `/view`, `/jobs`, `/userdata`, `/webhooks/*`, `/internal/*` **Included (cloud-only, codegen targets):** `/workspaces/*`, `/billing/*`, `/secrets/*`, `/assets/*`, `/tasks/*`, `/auth/*`, `/workflows/*`, `/workspace/*`, `/user`, `/settings/{key}`, `/tags`, `/feedback`, `/invite_code/*`, `/experiment/models/*`, `/global_subgraphs/*` This PR only sets up the codegen infrastructure. A follow-up PR should replace manually maintained types with imports from `@comfyorg/ingest-types`: | File | Lines | Current | Replace with | |------|-------|---------|-------------| | `src/platform/workspace/api/workspaceApi.ts` | ~270 | TS interfaces | `import type { ... } from '@comfyorg/ingest-types'` | | `src/platform/secrets/types.ts` | ~32 | TS interfaces | `import type { ... } from '@comfyorg/ingest-types'` | | `src/platform/assets/schemas/assetSchema.ts` | ~125 | Zod schemas | `import { ... } from '@comfyorg/ingest-types/zod'` | | `src/platform/assets/schemas/mediaAssetSchema.ts` | ~50 | Zod schemas | `import { ... } from '@comfyorg/ingest-types/zod'` | | `src/platform/tasks/services/taskService.ts` | ~70 | Zod schemas | `import { ... } from '@comfyorg/ingest-types/zod'` | | `src/platform/workspace/workspaceTypes.ts` | ~6 | TS interface | `export type { ... } from '@comfyorg/ingest-types'` | - [x] `pnpm generate` in `packages/ingest-types/` produces `types.gen.ts` and `zod.gen.ts` - [x] `pnpm typecheck` passes - [x] Pre-commit hooks pass (lint, typecheck, format) - [x] Generated Zod schemas validate correct data and reject invalid data - [x] No import conflicts with existing code (generated types are isolated in separate package) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: GitHub Action <action@github.com> feat: surface missing models in Error Tab for OSS and remove legacy dialog (#9921) - Surface missing models in the Error Tab for OSS environments, replacing the legacy modal dialog - Add Download button per model and Download All button in group header with file size display - Move download business logic from `components/dialog/content` to `platform/missingModel` - Remove legacy missing models dialog components and composable - **Pipeline**: Remove `isCloud` guard from `scanAllModelCandidates` and `surfaceMissingModels` so OSS detects missing models - **Grouping**: Group non-asset-supported models by directory in OSS instead of lumping into UNSUPPORTED - **UI**: Add Download button (matching Install Node Pack design) and Download All header button - **Store**: Add `folderPaths`/`fileSizes` state with setter methods, race condition guard - **Cleanup**: Delete `MissingModelsContent`, `MissingModelsHeader`, `MissingModelsFooter`, `useMissingModelsDialog`, `missingModelsUtils` - **Tests**: Add OSS/Cloud grouping tests, migrate Playwright E2E to Error Tab, improve test isolation - **Snapshots**: Reset Playwright screenshot expectations since OSS missing model error detection now causes red highlights on affected nodes - **Accessibility**: Add `aria-label` with model name, `aria-expanded` on toggle, warning icon for unknown category - [x] Unit tests pass (86 tests) - [x] TypeScript typecheck passes - [x] knip passes - [x] Load workflow with missing models in OSS → Error Tab shows missing models grouped by directory - [x] Download button triggers browser download with correct URL - [x] Download All button downloads all downloadable models - [x] Cloud environment behavior unchanged - [x] Playwright E2E: `pnpm test:browser:local -- --grep "Missing models in Error Tab"` https://github.com/user-attachments/assets/12f15e09-215a-4c58-87ed-39bbffd1359c ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9921-feat-surface-missing-models-in-Error-Tab-for-OSS-and-remove-legacy-dialog-3236d73d365081f0a9dfc291978f5ecf) by [Unito](https://www.unito.io) --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: github-actions <github-actions@github.com> fix: cloud subscribe redirect hangs waiting for billing init (#9965) Fix /cloud/subscribe route hanging indefinitely because billing context never initializes during the onboarding flow. - **What**: Replace passive `await until(isInitialized).toBe(true)` with explicit `await initialize()` in CloudSubscriptionRedirectView. Remove unused `until` import.  In the onboarding flow, `useTeamWorkspaceStore().activeWorkspace` is not set, so `useBillingContext`'s internal watch (which triggers `initialize()` on workspace change) enters the `!newWorkspaceId` branch — it resets `isInitialized` to `false` and returns without ever calling `initialize()`. The old code then awaited `isInitialized` becoming `true` forever. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9965-fix-cloud-subscribe-redirect-hangs-waiting-for-billing-init-3246d73d3650812d93ebd477c544fa0a) by [Unito](https://www.unito.io) Co-authored-by: Amp <amp@ampcode.com> feat: add TBT/frameDuration metrics and new perf test scenarios (#9910) Adds Total Blocking Time (TBT) and frame duration metrics to the performance testing infrastructure, plus three new test scenarios covering zoom, pan, and many-nodes-idle. - **`totalBlockingTimeMs`** — Computed from PerformanceObserver `longtask` entries: `sum(duration - 50ms)` for tasks >50ms. Measures main thread blocking. - **`frameDurationMs`** — Average frame duration via rAF timing (16.67ms = 60fps target). Measures rendering smoothness. | Scenario | Description | |---|---| | `canvas-zoom-sweep` | 10 zoom-in + 10 zoom-out cycles on default workflow | | `canvas-pan-many-nodes` | 10 pan sweeps over 100-node workflow | | `canvas-many-nodes-idle` | 2-second idle measurement with 100 nodes rendered | - `PerformanceHelper.ts`: Installs PerformanceObserver for longtask, collects TBT, measures frame duration via rAF - `perf-report.ts`: Reports TBT and frame duration in PR comment tables - `browser_tests/assets/perf/many_nodes_100.json`: 100-node (10×10 grid) test fixture - TBT collection clears entries at `startMeasuring()` and reads at `stopMeasuring()` — ensure no race with observer buffering - Frame duration sampling uses 10 frames — enough for signal without slowing tests Depends on: #9886, #9887 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9910-feat-add-TBT-frameDuration-metrics-and-new-perf-test-scenarios-3236d73d365081488ae3c594a8bf7cff) by [Unito](https://www.unito.io) fix: LGraphGroup paste position (#9962) Fix group paste position: groups now paste at the cursor location instead of on top of the original. - **What**: Added LGraphGroup offset handling in _deserializeItems() position adjustment loop, matching existing LGraphNode and Reroute behavior. Before: https://github.com/user-attachments/assets/e317af10-8009-4092-9d14-de79316cd853 After: https://github.com/user-attachments/assets/f4ffefd5-519a-4592-812c-c88e3b5940fd ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9962-fix-LGraphGroup-paste-position-3246d73d365081eea5b2e2507da861de) by [Unito](https://www.unito.io) fix: tree explorer nodes not filling parent container width (#9964) Fix tree explorer nodes not filling the full width of the sidebar container, causing text to overflow instead of truncating. - **What**: Add `min-w-0` to `TreeRoot` to allow flex shrinking within sidebar. Add `w-full` and `min-w-0` to tree node rows so absolutely-positioned virtualizer items fill the container width and text truncates correctly. <img width="365" height="749" alt="image" src="https://github.com/user-attachments/assets/320910f3-52ad-4634-a935-6bd1a40aea7f" /> The virtualizer renders each item with `position: absolute; left: 0` but no explicit width, so rows would size to content rather than filling the container. Adding `w-full` ensures rows stretch to 100% of the virtualizer container, and `min-w-0` allows proper flex shrinking for deep indentation levels. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9964-fix-tree-explorer-nodes-not-filling-parent-container-width-3246d73d36508138be38fdcac15ae4ef) by [Unito](https://www.unito.io) Co-authored-by: Amp <amp@ampcode.com> feat: add Copy URL button to missing model rows for OSS (#9966) 1.42.6 (#9986) Patch version increment to 1.42.6 **Base branch:** `main` ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9986-1-42-6-3256d73d365081a28bfad82022ce3440) by [Unito](https://www.unito.io) --------- Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com> Co-authored-by: github-actions <github-actions@github.com> fix: block missing e2e regression coverage in CodeRabbit (#9987) Make the CodeRabbit end-to-end regression coverage check actually block fix-like PRs until it is resolved or explicitly overridden by a requested reviewer, and harden the prompt so it evaluates only PR-local metadata. - **What**: Set the `End-to-end regression coverage for fixes` custom check mode from `warning` to `error` - **What**: Enable `reviews.request_changes_workflow` so CodeRabbit can block on failed `error` pre-merge checks - **What**: Set `reviews.pre_merge_checks.override_requested_reviewers_only` to `true` so only requested reviewers can bypass a failed check - **What**: Tighten the custom check instructions to use only PR metadata in review context, avoid shell commands, and avoid reverse-diff or base-branch file evaluation Confirm this is the intended CodeRabbit enforcement model for missing Playwright regression coverage on fix-like PRs and that the prompt wording is strict enough to avoid false positives from reversed diffs. fix: add reve and elevenlabs to icon safelist (#9990) Reve and ElevenLabs provider icons were not displaying in the node library because they were missing from the Tailwind icon safelist. - **What**: Add `reve` and `elevenlabs` to the `@source inline` safelist in `style.css` so `icon-[comfy--reve]` and `icon-[comfy--elevenlabs]` classes are generated. Add corresponding `PROVIDER_COLORS` entries in `categoryUtil.ts`. <img width="308" height="106" alt="image" src="https://github.com/user-attachments/assets/d488898a-fbad-4af0-8921-0e8ee7d4705a" /> <img width="308" height="78" alt="image" src="https://github.com/user-attachments/assets/2b3b7172-095b-415e-a49a-d303977e0abc" /> The SVG files already existed in `packages/design-system/src/icons/` but Tailwind's tree-shaking dropped the classes since they're only used dynamically via `getProviderIcon()`. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9990-fix-add-reve-and-elevenlabs-to-icon-safelist-3256d73d36508105994fcdd5d0568027) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com> fix: mask editor save shows blank image in Load Image node (#9984) Mask editor save was showing a blank image in the Load Image node (legacy nodes mode, not Nodes 2.0) because `updateNodeWithServerReferences` called `updateNodeImages`, which silently no-ops when the node has no pre-existing execution outputs. Replaced with `setNodeOutputs` which properly creates output entries regardless of prior state. **Affects:** Legacy nodes mode only. Nodes 2.0 (Vue Nodes) renders images via Vue components and is not affected. - Fixes #9983 - Fixes #9782 - Fixes #9952 | Commit | SHA | CI Status | Run | Purpose | |--------|-----|-----------|-----|---------| | `test: add failing test for mask editor save showing blank image` | `0ab66e8` | 🔴 [Red](https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/23125427860) | CI: Tests Unit **failure** | Proves the test catches the bug | | `fix: mask editor save shows blank image in Load Image node` | `564cc9c` | 🟢 [Green](https://github.com/Comfy-Org/ComfyUI_frontend/actions/runs/23127289891) | CI: Tests Unit **success** | Proves the fix resolves the bug | https://github.com/user-attachments/assets/8d5c36ce-2c5e-4609-b246-dcf896c4a8e7 https://github.com/user-attachments/assets/c8ae4f0e-3da0-40f2-a543-d1d5a6bce795 - [x] CI red on test-only commit - [x] CI green on fix commit - [ ] E2E regression test not added: mask editor save requires canvas pixel manipulation + server upload round-trip which is covered by the existing unit test mocking the full `save()` flow. The Playwright test infrastructure does not currently support mask editor interactions (draw + save). - [x] Manual verification (legacy nodes mode): Load Image → upload → mask editor → draw → save → verify image refreshes --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> fix: allow URL input for free tier users, gate on import button (#10024) - Remove free-tier restriction from the URL input field in `MissingModelUrlInput.vue` so it is always editable - Move the subscription check (`canImportModels`) to the Import button click handler — free-tier users see the upgrade modal only when they attempt to import - Extract inline ternary to named `handleImportClick` method for clarity - [x] Unit tests added (`MissingModelUrlInput.test.ts`) verifying: - URL input is always editable regardless of subscription tier - Import button calls `handleImport` for paid users - Import button calls `showUploadDialog` (upgrade modal) for free-tier users - [x] Verify URL input is editable for free-tier users on cloud - [x] Verify clicking Import as free-tier opens the subscription modal - [x] Verify paid users can import normally without changes Playwright E2E regression tests are impractical for this change because `MissingModelUrlInput` only renders when `isAssetSupported` is true, which requires `isCloud` — a compile-time constant (`__DISTRIBUTION__`). The OSS test build always sets `isCloud = false`, so the component never renders in the E2E environment. Unit tests with mocked feature flags provide equivalent behavioral coverage. fix: prevent subscription UI from rendering on non-cloud distributions (#9958) Prevent Plans & Pricing dialog, subscription buttons, and cloud-only menu items from appearing on desktop/localhost distributions. - **What**: Add `isCloud` guards to `useSubscriptionDialog.showPricingTable`, `TopbarSubscribeButton`, and `CurrentUserPopoverLegacy` so subscription UI only renders on cloud - **Tests**: 24 tests across 3 test files (1 modified, 2 new) covering cloud/non-cloud behavior - Guard placement in `CurrentUserPopoverLegacy.vue` — multiple `v-if` conditions updated to include `isCloud` - Early-return in `showPricingTable` as a defense-in-depth measure Fixes COM-16820 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9958-fix-prevent-subscription-UI-from-rendering-on-non-cloud-distributions-3246d73d365081559a9ee8650409c5b4) by [Unito](https://www.unito.io) Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com> fix: prevent animated preview duplication on Vue↔Litegraph switch (#9938) SaveAnimatedPNG/WEBP nodes show duplicate output previews when switching between Vue and Litegraph renderer modes. The `ANIM_PREVIEW_WIDGET` (`$$comfy_animation_preview`) DOM widget lacked `canvasOnly: true`, so `shouldRenderAsVue()` in the widget registry included it in Vue mode rendering. This caused both: 1. Vue's `ImagePreview.vue` (via `nodeMedia` computed from `nodeOutputStore`) 2. The legacy `ANIM_PREVIEW_WIDGET` DOM widget (rendered as `WidgetDOM`) to display simultaneously — duplicating the output preview. Add `canvasOnly: true` to the `ANIM_PREVIEW_WIDGET` options, matching the pattern used by `IMAGE_PREVIEW` widget in `useImagePreviewWidget.ts`. This ensures the legacy widget is filtered out in Vue mode by `shouldRenderAsVue()`, leaving `ImagePreview.vue` as the single source of truth. - All 539 vueNodes tests pass - All 22 nodeOutputStore tests pass - All 140 composables/node tests pass - Typecheck passes ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9938-fix-prevent-animated-preview-duplication-on-Vue-Litegraph-switch-3246d73d365081019bbfd7e33a9c14fb) by [Unito](https://www.unito.io) 1.43.0 (#10032) Minor version increment to 1.43.0 **Base branch:** `main` ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-10032-1-43-0-3256d73d3650818e8408d25fdf28de48) by [Unito](https://www.unito.io) Co-authored-by: christian-byrne <72887196+christian-byrne@users.noreply.github.com> Feat/3d thumbnail inline rendering (#9471) The previous approach generated thumbnails server-side and uploaded them as `model.glb.png` alongside the model file. This breaks on cloud deployments where output files are renamed to content hashes, severing the filename-based association between a model and its thumbnail. Replace the server-upload approach with client-side Three.js rendering ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9471-Feat-3d-thumbnail-inline-rendering-31b6d73d3650816fbd7dd05b507aa80d) by [Unito](https://www.unito.io) test: add FeatureFlagHelper and QueueHelper for E2E test infrastructure (#9554) Add 2 reusable test helpers for Playwright E2E tests, integrated into the ComfyPage fixture. These provide standardized patterns for mocking feature flags and queue state across all E2E tests. - **`FeatureFlagHelper.ts`** — manage localStorage `ff:` prefixed feature flags (`seedFlags` for init-time, `setFlags` for runtime) and mock `/api/features` route - **`QueueHelper.ts`** — mock `/api/queue` and `/api/history` routes with configurable running/pending counts and success/error job entries - **`ComfyPage.ts`** — integrate both helpers as `comfyPage.featureFlags` and `comfyPage.queue` - Helper API design: are `seedFlags`/`setFlags`/`mockServerFeatures` the right abstractions for feature flag testing? - Queue mock fidelity: does the mock history shape match real ComfyUI API responses closely enough? - These are test-only infrastructure — no production code changes. This is the base PR for the Playwright E2E coverage stack. Waves 1-4 all branch from this and can merge independently once this lands: - **→ This PR**: Test infrastructure helpers - #9555: Toasts, error overlay, selection toolbox, linear mode, selection rectangle - #9556: Node search, bottom panel, focus mode, job history, side panel - #9557: Errors tab, node headers, queue notifications, settings sidebar - #9558: Minimap, widget copy, floating menus, node library essentials --------- Co-authored-by: GitHub Action <action@github.com> feat: scaffold Astro 5 website app + design-system base.css - Create apps/website/ with Astro 5, Vue 3, Tailwind v4 integration - Static output, assetsPrefix /_website/, i18n (en + zh-CN) - Nx targets: dev, serve, build, preview, typecheck - Add base.css to design-system: brand tokens + Inter font-face only - Add catalog entries: astro, @astrojs/vue, @astrojs/check, nanostores, @nanostores/vue scaffold-01, scaffold-02 fix: add .gitignore and env.d.ts for Astro website app feat: add layout shell — SEO head, analytics, nav, footer - BaseLayout: OG/Twitter meta, canonical URL, GA4 GTM-NP9JM6K7, Vercel Analytics, ClientRouter for SPA navigation - SiteNav: Comfy logo, Enterprise/Gallery/About/Careers links, Comfy Cloud + Comfy Hub CTA buttons, mobile hamburger menu - SiteFooter: Product/Resources/Company/Legal columns, social icons (GitHub, Discord, X, Reddit, LinkedIn, Instagram) - Add @vercel/analytics to workspace catalog and website deps fix: address CodeRabbit review — ARIA wiring, absolute OG URLs, Analytics component - SiteNav: add aria-controls, aria-expanded, and id for mobile menu - BaseLayout: use absolute URLs for og:image and twitter:image - BaseLayout: replace inline inject() with official <Analytics /> component style: apply oxfmt formatting fix: remove unused deps from website package.json (knip) fix: clean up unused catalog entries from pnpm-workspace.yaml feat: add Wave 3 homepage sections (hero, social proof, pillars, testimonials, CTAs, manifesto, academy, placeholders)
Release Schedule
The project follows a structured release process for each minor version, consisting of three distinct phases:
-
Development Phase - 2 weeks
- Active development of new features
- Code changes merged to the development branch
-
Feature Freeze - 2 weeks
- No new features accepted
- Only bug fixes are cherry-picked to the release branch
- Testing and stabilization of the codebase
-
Publication
- Release is published at the end of the freeze period
- Version is finalized and made available to all users
Nightly Releases
Nightly releases are published daily at https://github.com/Comfy-Org/ComfyUI_frontend/releases.
To use the latest nightly release, add the following command line argument to your ComfyUI launch script:
--front-end-version Comfy-Org/ComfyUI_frontend@latest
Overlapping Release Cycles
The development of successive minor versions overlaps. For example, while version 1.1 is in feature freeze, development for version 1.2 begins simultaneously. Each feature has approximately 4 weeks from merge to ComfyUI stable release (2 weeks on main, 2 weeks frozen on RC).
Example Release Cycle
| Week | Date Range | Version 1.1 | Version 1.2 | Version 1.3 | Patch Releases |
|---|---|---|---|---|---|
| 1-2 | Mar 1-14 | Development | - | - | - |
| 3-4 | Mar 15-28 | Feature Freeze | Development | - | 1.1.0 through 1.1.13 (daily) |
| 5-6 | Mar 29-Apr 11 | Released | Feature Freeze | Development | 1.1.14+ (daily) 1.2.0 through 1.2.13 (daily) |
| 7-8 | Apr 12-25 | - | Released | Feature Freeze | 1.2.14+ (daily) 1.3.0 through 1.3.13 (daily) |
Release Summary
Major features
v1.5: Native translation (i18n)
ComfyUI now includes built-in translation support, replacing the need for third-party translation extensions. Select your language
in Comfy > Locale > Language to translate the interface into English, Chinese (Simplified), Russian, Japanese, Korean, or Arabic. This native
implementation offers better performance, reliability, and maintainability compared to previous solutions.
More details available here: https://blog.comfy.org/p/native-localization-support-i18n
v1.4: New mask editor
https://github.com/Comfy-Org/ComfyUI_frontend/pull/1284 implements a new mask editor.
v1.3.22: Integrated server terminal
Press Ctrl + ` to toggle integrated terminal.
https://github.com/user-attachments/assets/eddedc6a-07a3-4a83-9475-63b3977f6d94
v1.2.4: Node library sidebar tab
Drag & Drop
https://github.com/user-attachments/assets/853e20b7-bc0e-49c9-bbce-a2ba7566f92f
Filter
https://github.com/user-attachments/assets/4bbca3ee-318f-4cf0-be32-a5a5541066cf
v1.2.0: Queue/History sidebar tab
https://github.com/user-attachments/assets/86e264fe-4d26-4f07-aa9a-83bdd2d02b8f
v1.1.0: Node search box
Fuzzy search & Node preview
Release link with shift
https://github.com/user-attachments/assets/a1b2b5c3-10d1-4256-b620-345de6858f25
QoL changes
v1.3.32: **Litegraph** Nested group
https://github.com/user-attachments/assets/f51adeb1-028e-40af-81e4-0ac13075198a
v1.3.24: **Litegraph** Group selection
https://github.com/user-attachments/assets/e6230a94-411e-4fba-90cb-6c694200adaa
v1.3.6: **Litegraph** Toggle link visibility
v1.3.4: **Litegraph** Auto widget to input conversion
Dropping a link of correct type on node widget will automatically convert the widget to input.
v1.3.4: **Litegraph** Canvas pan mode
The canvas becomes readonly in pan mode. Pan mode is activated by clicking the pan mode button on the canvas menu or by holding the space key.
v1.3.1: **Litegraph** Shift drag link to create a new link
v1.2.44: **Litegraph** Double click group title to edit
https://github.com/user-attachments/assets/5bf0e2b6-8b3a-40a7-b44f-f0879e9ad26f
v1.2.39: **Litegraph** Group selected nodes with Ctrl + G
https://github.com/user-attachments/assets/7805dc54-0854-4a28-8bcd-4b007fa01151
v1.2.38: **Litegraph** Double click node title to edit
https://github.com/user-attachments/assets/d61d5d0e-f200-4153-b293-3e3f6a212b30
v1.2.7: **Litegraph** drags multiple links with shift pressed
https://github.com/user-attachments/assets/68826715-bb55-4b2a-be6e-675cfc424afe
https://github.com/user-attachments/assets/c142c43f-2fe9-4030-8196-b3bfd4c6977d
v1.2.2: **Litegraph** auto connects to correct slot
Before
https://github.com/user-attachments/assets/c253f778-82d5-4e6f-aec0-ea2ccf421651
After
https://github.com/user-attachments/assets/b6360ac0-f0d2-447c-9daa-8a2e20c0dc1d
v1.1.8: **Litegraph** hides text overflow on widget value
https://github.com/user-attachments/assets/5696a89d-4a47-4fcc-9e8c-71e1264943f2
Developer APIs
v1.6.13: prompt/confirm/alert replacements for ComfyUI desktop
Several browser-only APIs are not available in ComfyUI desktop's electron environment.
window.promptwindow.confirmwindow.alert
Please use the following APIs as replacements.
// window.prompt
window['app'].extensionManager.dialog
.prompt({
title: 'Test Prompt',
message: 'Test Prompt Message'
})
.then((value: string) => {
// Do something with the value user entered
})
// window.confirm
window['app'].extensionManager.dialog
.confirm({
title: 'Test Confirm',
message: 'Test Confirm Message'
})
.then((value: boolean) => {
// Do something with the value user entered
})
// window.alert
window['app'].extensionManager.toast.addAlert('Test Alert')
v1.3.34: Register about panel badges
app.registerExtension({
name: 'TestExtension1',
aboutPageBadges: [
{
label: 'Test Badge',
url: 'https://example.com',
icon: 'pi pi-box'
}
]
})
v1.3.22: Register bottom panel tabs
app.registerExtension({
name: 'TestExtension',
bottomPanelTabs: [
{
id: 'TestTab',
title: 'Test Tab',
type: 'custom',
render: (el) => {
el.innerHTML = '<div>Custom tab</div>'
}
}
]
})
v1.3.22: New settings API
Legacy settings API.
// Register a new setting
app.ui.settings.addSetting({
id: 'TestSetting',
name: 'Test Setting',
type: 'text',
defaultValue: 'Hello, world!'
})
// Get the value of a setting
const value = app.ui.settings.getSettingValue('TestSetting')
// Set the value of a setting
app.ui.settings.setSettingValue('TestSetting', 'Hello, universe!')
New settings API.
// Register a new setting
app.registerExtension({
name: 'TestExtension1',
settings: [
{
id: 'TestSetting',
name: 'Test Setting',
type: 'text',
defaultValue: 'Hello, world!'
}
]
})
// Get the value of a setting
const value = app.extensionManager.setting.get('TestSetting')
// Set the value of a setting
app.extensionManager.setting.set('TestSetting', 'Hello, universe!')
v1.3.7: Register commands and keybindings
Extensions can call the following API to register commands and keybindings. Do note that keybindings defined in core cannot be overwritten, and some keybindings are reserved by the browser.
app.registerExtension({
name: 'TestExtension1',
commands: [
{
id: 'TestCommand',
function: () => {
alert('TestCommand')
}
}
],
keybindings: [
{
combo: { key: 'k' },
commandId: 'TestCommand'
}
]
})
v1.3.1: Extension API to register custom topbar menu items
Extensions can call the following API to register custom topbar menu items.
app.registerExtension({
name: 'TestExtension1',
commands: [
{
id: 'foo-id',
label: 'foo',
function: () => {
alert(1)
}
}
],
menuCommands: [
{
path: ['ext', 'ext2'],
commands: ['foo-id']
}
]
})
v1.2.27: Extension API to add toast message
iExtensions can call the following API to add toast messages.
app.extensionManager.toast.add({
severity: 'info',
summary: 'Loaded!',
detail: 'Extension loaded!',
life: 3000
})
Documentation of all supported options can be found here: https://primevue.org/toast/#api.toast.interfaces.ToastMessageOptions
v1.2.4: Extension API to register custom sidebar tab
Extensions now can call the following API to register a sidebar tab.
app.extensionManager.registerSidebarTab({
id: 'search',
icon: 'pi pi-search',
title: 'search',
tooltip: 'search',
type: 'custom',
render: (el) => {
el.innerHTML = '<div>Custom search tab</div>'
}
})
The list of supported icons can be found here: https://primevue.org/icons/#list
We will support custom icons later.
v1.10.9: Selection Toolbox API
Extensions can register commands that appear in the selection toolbox when specific items are selected on the canvas.
app.registerExtension({
name: 'TestExtension1',
commands: [
{
id: 'test.selection.command',
label: 'Test Command',
icon: 'pi pi-star',
function: () => {
// Command logic here
}
}
],
// Return an array of command IDs to show in the selection toolbox
// when an item is selected
getSelectionToolboxCommands: (selectedItem) => ['test.selection.command']
})
The selection toolbox will display the command button when items are selected:
Contributing
We welcome contributions to ComfyUI Frontend! Please see our Contributing Guide for:
- Ways to contribute (code, documentation, testing, community support)
- Development setup and workflow
- Code style guidelines
- Testing requirements
- How to submit pull requests
- Backporting fixes to release branches
Development
For detailed development setup, testing procedures, and technical information, please refer to CONTRIBUTING.md.
i18n
See locales/README.md for details.
Storybook
See .storybook/README.md for component development and visual testing documentation.
Troubleshooting
For comprehensive troubleshooting and technical support, please refer to our official documentation:
- General Troubleshooting Guide - Common issues, performance optimization, and reporting bugs
- Custom Node Issues - Debugging custom node problems and conflicts
- Desktop Installation Guide - Desktop-specific installation and troubleshooting