## Refactor conflict detection system and move to manager extension
### Description
This PR refactors the conflict detection system, moving it from the
global composables to the manager extension folder for better code
organization. Additionally, it improves test type safety and adds
comprehensive test coverage for utility functions.
### Main Changes
#### 📦 Code Organization
- **Moved conflict detection to manager extension** - Relocated all
conflict detection related composables, stores, and utilities from
global scope to `/workbench/extensions/manager/` for better modularity
(https://github.com/Comfy-Org/ComfyUI_frontend/pull/5722)
- **Moved from** `src/composables/useConflictDetection.ts` **to**
`src/workbench/extensions/manager/composables/useConflictDetection.ts`
- Moved related stores and composables to maintain cohesive module
structure
#### ♻️ Refactoring
- **Extracted utility functions** - Split conflict detection logic into
separate utility modules:
- `conflictUtils.ts` - Conflict consolidation and summary generation
- `systemCompatibility.ts` - OS and accelerator compatibility checking
- `versionUtil.ts` - Version compatibility checking
- **Removed duplicate state management** - Cleaned up redundant state
and unused functions
- **Improved naming conventions** - Renamed functions for better clarity
- **Removed unused system environment code** - Cleaned up deprecated
code
#### 🔧 Test Improvements
- **Fixed TypeScript errors** in all test files - removed all `any` type
usage
- **Added comprehensive test coverage**:
- `conflictUtils.test.ts` - 299 lines of tests for conflict utilities
- `systemCompatibility.test.ts` - 270 lines of tests for compatibility
checking
- `versionUtil.test.ts` - 342 lines of tests for version utilities
- **Updated mock objects** to match actual implementations
- **Aligned with backend changes** - Updated SystemStats structure to
include `pytorch_version`, `embedded_python`,
`required_frontend_version`
#### 🐛 Bug Fixes
- **Fixed OS detection bug** - Resolved issue where 'darwin' was
incorrectly matched as 'Windows' due to containing 'win' substring
- **Fixed import paths** - Updated all import paths after moving to
manager extension
- **Fixed unused exports** - Removed all unused function exports
- **Fixed lint errors** - Resolved all ESLint and Prettier issues
### File Structure Changes
```
Before:
src/
├── composables/
│ └── useConflictDetection.ts (1374 lines)
└── types/
After:
src/
├── utils/
│ ├── conflictUtils.ts (114 lines)
│ ├── systemCompatibility.ts (125 lines)
│ └── versionUtil.ts (enhanced)
└── workbench/extensions/manager/
├── composables/
│ ├── useConflictDetection.ts (758 lines)
│ └── [other composables]
└── stores/
└── conflictDetectionStore.ts
```
### Testing
All tests pass successfully:
- ✅ **155 test files passed**
- ✅ **2209 tests passed**
- ⏩ 19 skipped (intentionally skipped subgraph-related tests)
### Impact
- **Better code organization** - Manager-specific code is now properly
isolated
- **Improved maintainability** - Smaller, focused utility functions are
easier to test and maintain
- **Enhanced type safety** - No more `any` types in tests
- **Comprehensive test coverage** - All utility functions are thoroughly
tested
### Commits in this PR
1. OS detection bug fix and refactor
2. Remove unused system environment code
3. Improve function naming
4. Refactor conflict detection
5. Remove duplicate state and unused functions
6. Fix unused function exports
7. Move manager features to workbench extension folder
8. Fix import paths
9. Rename systemCompatibility file
10. Improve test type safety
11. Apply ESLint and Prettier fixes
## Screenshots (if applicable)
[screen-capture.webm](https://github.com/user-attachments/assets/b4595604-3761-4d98-ae8e-5693cd0c95bd)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5436-Manager-refactor-conflict-detect-2686d73d36508186ba06f57dae3656e5)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Fixed Vue node output restoration by consolidating state management
through the node output store.
## Changes
- **What**: Refactored node output cleanup and restoration logic in
`ChangeTracker` and `ComfyApp` to use centralized store methods
- **Breaking**: Removed direct manipulation of `app.nodeOutputs` in
favor of store-managed state
## Review Focus
State synchronization between `app.nodeOutputs` and `nodeOutputs.value`
during restore/reset operations, ensuring Vue reactivity is maintained.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5788-fix-restoring-outputs-in-Vue-nodes-persisting-node-outputs-when-switching-between-workfl-27a6d73d365081b39411fed7479d8ac5)
by [Unito](https://www.unito.io)
## Summary
Split tailwind utils out to a shared package within the monorepo.
## Changes
- Creates `@comfyorg/tailwind-utils` package
- Does not require export, publishing, etc
- Uses `export` to ensure this change does not impact other PRs (many
imports to update)
- If we _want_ to update all imports, there are two commits ready to be
re-applied
- e.g. `git revert 80960c2a82c0d1ac06eee1bb83ac333216b2b376`
## Review Focus
- Is this pattern desirable?
- Should we just include this in a broader design-system split? I kind
of vote yes, but also it's a good small, first step.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5777-Split-Tailwind-utility-functions-out-to-a-shared-package-2796d73d3650815f976fc73b4fb86ef3)
by [Unito](https://www.unito.io)
## Summary
Added mute state support to Vue nodes with visual feedback and keyboard
shortcut functionality.
## Changes
- **What**: Implemented mute state (mode 2) for Vue nodes with opacity
styling and `Ctrl+M` hotkey support
## Review Focus
Visual consistency between bypass and mute states, and keyboard shortcut
conflict detection with existing hotkeys.
## Test Coverage
- Single node mute/unmute with `Ctrl+M` hotkey
- Multi-selection mute/unmute operations
- Visual state verification with opacity changes
## Related
- https://github.com/Comfy-Org/ComfyUI_frontend/pull/5715
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5770-Add-muted-state-to-Vue-nodes-2796d73d36508143b3edfbcb782de7c1)
by [Unito](https://www.unito.io)
## Summary
UseNewMenu has been defaulted to Top in the app for over a year;
Playwright’s test default lagged behind. This PR aligns the test default
with reality and keeps legacy specs stable.
## Changes
- tests(e2e): default to 'Top' via fixture; specs that previously relied
on the old implicit default now explicitly set 'Comfy.UseNewMenu' to
'Disabled'.
- docs(browser-tests): remove outdated README note suggesting tests set
'Top' manually.
## Review Focus
- Intentional uses of 'Top' and 'Bottom' remain unchanged.
- Confirm ComfyPage default remains 'Top' (see
browser_tests/fixtures/ComfyPage.ts).
## Screenshots (if applicable)
N/A
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5746-test-e2e-align-test-default-menu-to-Top-make-legacy-specs-explicit-2786d73d365081218d06c1346f3ae18e)
by [Unito](https://www.unito.io)
---------
Co-authored-by: github-actions <github-actions@github.com>
## Summary
I want to take a more general look at `comfyApp.graph.onTrigger` but
this is the cleanest fix I could come up with for #5694.
I will explore simplifying onTrigger in a separate PR.
## Changes
1. Create a `node:slot-errors:changed` trigger.
2. Trigger it if we find any of the node slots have errors.
3. Check each node to see if there is any error present.
4. Add an error class if there are.
## Screenshots (if applicable)
Working error states!
<img width="1049" height="987" alt="Screenshot 2025-09-23 at 8 40 04 PM"
src="https://github.com/user-attachments/assets/30e13283-129c-4d9c-b342-e7037582998a"
/>
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5758-fix-properly-show-error-states-2786d73d365081cbbf62c314c7f5f380)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Alexander Brown <drjkl@comfy.org>
## Summary
This PR fixes a flaky test in the load audio widget spec that was
causing intermittent failures in CI.
## Problem
The test was attempting to trigger a file chooser event before the
widget's upload button was fully rendered and ready for interaction,
leading to race conditions.
## Solution
Added an explicit wait for the widget element to be visible before
triggering the file chooser, ensuring the DOM is ready for interaction.
## Changes
- Added `waitFor` to verify widget visibility before file upload
- Ensures proper synchronization between DOM updates and test actions
## Test plan
- [x] Browser tests pass locally
- [x] Typecheck passes
- [ ] CI tests pass
🤖 Generated with [Claude Code](https://claude.ai/code)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5755-bugfix-Stabilize-flaky-load-audio-widget-test-2786d73d365081cebaefdc6470333c5d)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
- Added missing directories and files to tsconfig.json to ensure
complete TypeScript type checking coverage
- Expanded config file patterns to include all .mts configuration files
- Verified all 908 TypeScript files in the project are now properly
covered
## Changes
- Added `scripts/**/*.ts` to cover all TypeScript files in scripts
directory (i18n collection, CI/CD scripts)
- Added `build/**/*.ts` to cover customIconCollection.ts and future
build scripts
- Changed `vite.config.mts` to `*.config.mts` to include all vite config
files (vite.electron.config.mts, vite.types.config.mts)
## Test plan
- [x] Run `pnpm typecheck` to verify no TypeScript errors
- [x] Verified all TypeScript files are covered by tsconfig patterns
- [x] browser_tests/ directory confirmed to have its own extending
tsconfig
🤖 Generated with [Claude Code](https://claude.ai/code)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5655-chore-tsconfig-ensure-complete-TypeScript-coverage-for-all-project-files-2736d73d36508103acbadc53ca2b2913)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: filtered <176114999+webfiltered@users.noreply.github.com>
## Summary
Merges ComfyUI devtools components into the ComfyUI frontend monorepo to
consolidate development tools.
## Changes
- Added devtools components from ComfyUI repository
- Integrated development nodes and utilities
- Consolidated fake model assets for testing
## Related Issues
Fixes#4683
## Testing
- Devtools components are now available within the frontend monorepo
- Development workflow remains consistent
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
Replaced reactive (Vue-based) widget LOD with CSS visibility control.
Performance doesn't dramatically improve, but we avoid the mount/unmount
overhead during zoom/pan operations. This PR implements the visual
component of LOD—complex widgets that need lifecycle management will be
addressed separately.
### Problem & Solution
Problem: we want LOD to improve rendering performance and visual
feedback but discovered using reactivity in the current setup for it
meant mounting/unmounting caused worse lag than the performance it aimed
to fix. Switching to render all the details all the time but using css
visibility proved to be the best solution. However, it doesn't improve
rendering performance by much because the GPU texture size is the
bottleneck (from TransformPane.vue CSS transforms) and not
rasterization.
Solution: Keep all nodes/widgets mounted, use CSS visibility: hidden for
LOD. Trade memory for performance stability during zoom/pan/drag
operations.
### Technical Decision
We chose Performance > Memory:
- CSS transforms create a single GPU texture whose size depends on node
count, not widget complexity
- Mounting/unmounting hundreds of widgets during zoom = noticeable lag
from Vue VDOM diffing (since all components are mounted all the time
because of viewport culling challenge/trade off see
https://github.com/Comfy-Org/ComfyUI_frontend/pull/5510.)
- CSS visibility changes = no reactivity overhead, smooth interactions
- Result: Similar performance, but without interaction stutters
This is the visual layer only. If we want a hook into the LOD state per
node / widget that would be the next follow up system to implement.
### Next Steps (maybe)
- Chunked (split up single Transform Pane transform layer) when
rendering 1000+ nodes (maybe)
- ~~Selective unmounting API for widgets that register as "expensive"~~
- ~~Client bound hydration system~~
## Screenshots (if applicable)
<!-- Add screenshots or video recording to help explain your changes -->
<img width="1355" height="960" alt="image"
src="https://github.com/user-attachments/assets/41474d1b-9dbe-4240-a8cf-f4c9ff51d8e0"
/>
<img width="1354" height="963" alt="image"
src="https://github.com/user-attachments/assets/9f55edaa-5858-41b9-b6a8-c2d37e1649bd"
/>
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5631-feat-vue-nodes-LOD-system-2726d73d365081c6a6c4e14aa634f19c)
by [Unito](https://www.unito.io)
---------
Co-authored-by: github-actions <github-actions@github.com>
## Summary
This reverts PR #5614 which moved VueFire persistence configuration to
initialization.
## Reason for Revert
It breaks Google SSO login with error:
```
useErrorHandling.ts:12 FirebaseError: Firebase: Error (auth/argument-error).
at createErrorInternal (index-c92d61ad.js:506:41)
at _assert (index-c92d61ad.js:512:15)
at _withDefaultResolver (index-c92d61ad.js:9237:5)
at signInWithPopup (index-c92d61ad.js:9457:30)
at executeAuthAction.createCustomer (firebaseAuthStore.ts:263:25)
at executeAuthAction (firebaseAuthStore.ts:223:28)
at Proxy.loginWithGoogle (firebaseAuthStore.ts:262:5)
at Proxy.wrappedAction (pinia.mjs:1405:26)
at useFirebaseAuthActions.ts:104:28
at Object.signInWithGoogle (useErrorHandling.ts:39:22)
```
## Changes
- Reverts commit ea4e57b60 "Move VueFire persistence configuration to
initialization (#5614)"
- Restores previous Firebase auth persistence behavior
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5729-Revert-Move-VueFire-persistence-configuration-to-initialization-5614-2776d73d3650814c9b80d9c67c852874)
by [Unito](https://www.unito.io)
## Summary
Refactored `onUserResolved` function in auth composable to use VueUse
`whenever` utility instead of manual watch implementation and use
`immediate` option instead of invoking manually before creating watcher.
## Changes
- **What**: Replaced manual watch + immediate check pattern with [VueUse
whenever](https://vueuse.org/shared/whenever/) utility in
`useCurrentUser.ts:37`
## Review Focus
Behavioral equivalence verification - `whenever` with `immediate: true`
should maintain identical callback timing and cleanup semantics.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5718-refactor-Simplify-current-user-resolved-hook-implementation-2766d73d365081008b6de156dd78f940)
by [Unito](https://www.unito.io)
## Summary
Fixed Vue node keybinding target element ID to enable
bypass/pin/collapse hotkeys in both LiteGraph and Vue rendering modes.
Also fixed a bug when starting in litegraph mode => switching to Vue
nodes without reloading => `graph.onTrigger` is set to `undefined` which
interferes with proper setup of node data instrumentation, among other
things.
## Changes
- **What**: Updated keybinding `targetElementId` from `graph-canvas` to
`graph-canvas-container` for node manipulation commands (parent of both
the canvas and transform pane -- vue nodes container).
- **What**: Added conditional `onTrigger` handler restoration in slot
layout sync to prevent Vue node manager conflicts
## Review Focus
Event handler precedence between Vue nodes and LiteGraph systems during
mode switching, ensuring hotkeys work consistently across rendering
modes.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5715-fix-bypass-hotkey-in-vue-nodes-and-fix-node-data-instrumentation-setup-issue-when-switchi-2756d73d3650815c8ec8d5e4d06232e3)
by [Unito](https://www.unito.io)
## Summary
Fixes https://github.com/Comfy-Org/ComfyUI_frontend/issues/5688 by
adding shift modifier support for multi-selecting Vue nodes, enabling
standard shift+click selection behavior alongside existing
ctrl/cmd+click.
## Changes
- **What**: Updated Vue node event handlers to include `event.shiftKey`
in multi-select logic
- **Testing**: Added browser tests for both ctrl and shift modifier
selection behaviors
## Review Focus
Multi-select behavior consistency across different input modifiers and
platform compatibility (Windows/Mac/Linux shift key handling).
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5714-fix-using-shift-modifier-to-de-select-Vue-nodes-2756d73d365081bcb5e0fe80eacdb2f0)
by [Unito](https://www.unito.io)
## Summary
Don't route events up through GraphCanvas if the component itself can
handle the changes
## Changes
- **What**: Reduce the indirect access or action dispatch to
composables/stores.
## Review Focus
The behavior should be either equivalent or a little snappier than
before. Also, the local state in LGraphNode has (almost) all been
removed in favor of reacting to the nodeData prop.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5709-Refactor-Let-LGraphNode-handle-more-events-itself-2756d73d365081e6a88ce6241bceecc0)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
## Summary
Prerequisite refactor/cleanup to use a global store instead of having
nodes throw up events to a parent component that stores a reference to a
singleton service that itself bootstraps and synchronizes with a
separate service to maintain a partially reactive but not fully reactive
set of states that describe some but not all aspects of the nodes on
either the litegraph, the vue side, or both.
## Changes
- **What**: Refactoring, the behavior should not change.
- **Dependencies**: A type utility to help with Vue component props
## Review Focus
Is there something about the current structure that this could affect
that would not be caught by our tests or using the application?
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5695-Refactor-Composable-disentangling-2746d73d365081e6938ce656932f3e36)
by [Unito](https://www.unito.io)
## Summary
Add asset browser dialog integration for combo widgets with full
animation support and proper state management.
(Thank you Claude from saving me me from merge conflict hell on this
one.)
## Changes
- Widget integration: combo widgets now use AssetBrowserModal for
eligible asset types
- Dialog animations: added animateHide() for smooth close transitions
- Async operations: proper sequencing of widget updates and dialog
animations
- Service layer: added getAssetsForNodeType() and getAssetDetails()
methods
- Type safety: comprehensive TypeScript types and error handling
- Test coverage: unit tests for all new functionality
- Bonus: fixed the hardcoded labels in AssetFilterBar
Widget behavior:
- Shows asset browser button for eligible widgets when asset API enabled
- Handles asset selection with proper callback sequencing
- Maintains widget value updates and litegraph notification
## Review Focus
I will call out some stuff inline.
## Screenshots
https://github.com/user-attachments/assets/9d3a72cf-d2b0-445f-8022-4c49daa04637
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-5629-feat-integrate-asset-browser-with-widget-system-2726d73d365081a9a98be9a2307aee0b)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>