## Summary
Migrate keybindings domain to `src/platform/keybindings/` following DDD
principles.
## Changes
- **What**: Consolidate keybinding-related code (types, store, service,
defaults, reserved keys) into a single domain module with flat structure
- Extracted `KeyComboImpl` and `KeybindingImpl` classes into separate
files
- Updated all consumers to import from new location
- Colocated tests with source files
- Updated stores/README.md and services/README.md to remove migrated
entries
## Review Focus
- Verify all import paths were updated correctly
- Check that the flat structure is appropriate (vs nested core/data/ui
layers)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8369-refactor-migrate-keybindings-to-DDD-structure-2f66d73d36508120b169dc737075fb45)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
## Summary
Adds support for creating Chatterbox TTS nodes when clicking Chatterbox
models in the Cloud asset browser.
## Changes
### modelToNodeStore.ts
- Add `findProvidersWithFallback()` helper for hierarchical model type
lookups (e.g., `parent/child` falls back to `parent`)
- Register 4 Chatterbox model directories with empty widget keys:
- `chatterbox/chatterbox` → `FL_ChatterboxTTS`
- `chatterbox/chatterbox_turbo` → `FL_ChatterboxTurboTTS`
- `chatterbox/chatterbox_multilingual` → `FL_ChatterboxMultilingualTTS`
- `chatterbox/chatterbox_vc` → `FL_ChatterboxVC`
### createModelNodeFromAsset.ts
- Skip widget assignment when `provider.key` is empty (for nodes that
auto-load models without a widget selector)
### Tests
- Add tests for hierarchical fallback behavior
- Add tests for empty widget key (auto-load nodes)
- Add Chatterbox node types to mock data
## Notes
- Empty `key` convention: Chatterbox nodes auto-load their models and
don't have a model selector widget, so we register them with `key: ''`
and skip the widget assignment step
- Hierarchical fallback only goes one level deep (`a/b/c` → `a`, not
`a/b`)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8418-feat-add-Chatterbox-model-support-for-Cloud-asset-browser-2f76d73d365081be822bc369b155f099)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Fix shift+click range selection not properly deselecting assets when
selecting a smaller range, and improve selection performance.
## Changes
- **Bug Fix**: Shift+click now replaces selection with the new range
instead of combining with existing selection
- **Performance**: Remove unnecessary `.every()` check in `setSelection`
(O(n) → O(1))
- **Tests**: Add 23 unit tests for asset selection logic
## Test Plan
- [x] Click 1st asset → only 1st selected
- [x] Shift+click 3rd asset → items 1-3 selected
- [x] Shift+click 1st asset → only 1st selected (was broken, now fixed)
- [x] All 23 new unit tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8396-bugfix-Fix-shift-click-deselection-in-asset-panel-2f76d73d3650814ca060d1e6a40cf6d4)
by [Unito](https://www.unito.io)
## Summary
This PR adds two related features for subgraph blueprints:
### 1. Protect Global Blueprints from Deletion
- Added `isGlobalBlueprint()` helper that distinguishes blueprints by
`python_module` field
- User blueprints have `python_module: 'blueprint'`
- Global (installed) blueprints have `python_module` set to the node
pack name
- Guarded `deleteBlueprint()` to show a warning toast for global
blueprints
- Hidden delete menu in node library for global blueprints
### 2. Category Support for Blueprints
- User blueprints now use category `Subgraph Blueprints/User`
- Global blueprints use `Subgraph Blueprints/{category}` if category is
provided, otherwise `Subgraph Blueprints`
- Extended `GlobalSubgraphData.info` type with optional `category` field
- Added `category` to `zSubgraphDefinition` schema
## Files Changed
- `src/stores/subgraphStore.ts` - Core logic for both features
- `src/stores/subgraphStore.test.ts` - Tests for `isGlobalBlueprint`
- `src/components/sidebar/tabs/nodeLibrary/NodeTreeLeaf.vue` - Hide
delete menu for global blueprints
- `src/scripts/api.ts` - Extended `GlobalSubgraphData` type
- `src/platform/workflow/validation/schemas/workflowSchema.ts` - Added
category to schema
- `src/locales/en/main.json` - Added translation key
## Testing
- ✅ `pnpm typecheck` passed
- ✅ `pnpm lint` passed
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8378-feat-add-category-support-for-blueprints-and-protect-global-blueprints-2f66d73d36508137aa67c2d88c358b69)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: AustinMroz <austin@comfy.org>
## Summary
- Fix auth related race conditions with a new WorkspaceAuthGate in
App.vue
- De dup initialization calls
- Add state machine to track state of refreshRemoteConfig
- Fix websocket not using new workspace jwt
- Misc improvments
## Changes
- **What**: Mainly WorkspaceAuthGate.vue
- **Breaking**: <!-- Any breaking changes (if none, remove this line)
-->
- **Dependencies**: <!-- New dependencies (if none, remove this line)
-->
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8350-Feat-workspaces-5-auth-gate-check-2f66d73d365081b1a49afcd418fab3e7)
by [Unito](https://www.unito.io)
## Summary
Refactors bootstrap and lifecycle management to parallelize
initialization, use Vue best practices, and fix a logout state bug.
## Changes
### Bootstrap Store (`bootstrapStore.ts`)
- Extract early bootstrap logic into a dedicated store using
`useAsyncState`
- Parallelize settings, i18n, and workflow sync loading (previously
sequential)
- Handle multi-user login scenarios by deferring settings/workflows
until authenticated
### GraphCanvas Refactoring
- Move non-DOM composables (`useGlobalLitegraph`, `useCopy`, `usePaste`,
etc.) to script setup level for earlier initialization
- Move `watch` and `whenever` declarations outside `onMounted` (Vue best
practice)
- Use `until()` from VueUse to await bootstrap store readiness instead
of direct async calls
### GraphView Simplification
- Replace manual `addEventListener`/`removeEventListener` with
`useEventListener`
- Replace `setInterval` with `useIntervalFn` for automatic cleanup
- Move core command registration to script setup level
### Bug Fix
Using `router.push()` for logout caused `isSettingsReady` to persist as
`true`, making new users inherit the previous user's cached settings.
Reverted to `window.location.reload()` with TODOs for future store reset
implementation.
## Testing
- Verified login/logout cycle clears settings correctly
- Verified bootstrap sequence completes without errors
---------
Co-authored-by: Amp <amp@ampcode.com>
## Summary
Removes all `as unknown as Type` double-cast patterns from group 4 files
as part of the ongoing TypeScript cleanup effort.
## Changes
### Type Safety Improvements
- Replaced `as unknown as Type` with `as Partial<Type> as Type` for
valid mock objects
- Added proper null/undefined validation in `Subgraph.addInput()` and
`Subgraph.addOutput()`
- Updated test expectations to match new validation behavior
### Files Modified (17 files)
**Core Implementation:**
- `src/lib/litegraph/src/LGraph.ts` - Added input validation for
subgraph add methods
- `src/lib/litegraph/src/interfaces.ts` - Cleaned up type definitions
- `src/lib/litegraph/src/subgraph/ExecutableNodeDTO.ts` - Improved type
safety
- `src/platform/telemetry/types.ts` - Better type definitions
- `src/platform/telemetry/utils/surveyNormalization.ts` - Type cleanup
**Test Files:**
- `src/lib/litegraph/src/subgraph/SubgraphEdgeCases.test.ts` - Updated
to expect validation errors
- `src/lib/litegraph/src/subgraph/SubgraphMemory.test.ts` - Proper mock
typing
- `src/lib/litegraph/src/subgraph/SubgraphNode.test.ts` - Type
improvements
- `src/lib/litegraph/src/subgraph/SubgraphNode.titleButton.test.ts` -
Mock type fixes
- `src/lib/litegraph/src/subgraph/SubgraphSlotVisualFeedback.test.ts` -
Proper typing
- `src/lib/litegraph/src/subgraph/SubgraphWidgetPromotion.test.ts` -
Type cleanup
- `src/lib/litegraph/src/utils/textUtils.test.ts` - Mock improvements
- `src/lib/litegraph/src/widgets/ComboWidget.test.ts` - Type safety
updates
- `src/platform/assets/services/assetService.test.ts` - Type
improvements
- `src/platform/settings/composables/useSettingSearch.test.ts` - Mock
type fixes
- `src/platform/settings/settingStore.test.ts` - Type cleanup
- `src/platform/telemetry/utils/__tests__/surveyNormalization.test.ts` -
Type improvements
## Testing
- ✅ All modified test files pass
- ✅ TypeScript compilation passes
- ✅ Linting passes
## Related
Part of the TypeScript cleanup effort. Follows patterns from groups 1-3.
Previous PRs:
- Group 1: (merged)
- Group 2: (merged)
- Group 3: #8304
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8314-Road-to-No-Explicit-Any-Part-8-Group4-2f46d73d36508172a9d4e53b2c5cbadd)
by [Unito](https://www.unito.io)
## Summary
- Keep all drafts in localStorage, mirroring the logic from VSCode.
- Fix a bug where newly created blank workflow tabs would incorrectly
restore as defaultGraph instead of blankGraph after page refresh.
Resolves https://github.com/Comfy-Org/desktop/issues/910, Resolves
https://github.com/Comfy-Org/ComfyUI_frontend/issues/4057, Fixes
https://github.com/Comfy-Org/ComfyUI_frontend/issues/3665
## Changes
### What
- Fix `restoreWorkflowTabsState` to parse and pass workflow data from
drafts when recreating temporary workflows
- Add error handling for invalid draft data with fallback to default
workflow
- Fix E2E test `should not serialize color adjustments in workflow` to
wait for workflow persistence before assertions
- Add proper validation for workflow nodes array in test assertions
### Breaking
- None
### Dependencies
- No new dependencies added
## Review Focus
1. **Workflow restoration**: Verify that blank workflows correctly
restore as blankGraph after page refresh
2. **Error handling**: Check that invalid draft data gracefully falls
back to default workflow
3. **Test coverage**: Ensure E2E test correctly waits for workflow
persistence before checking node properties
4. **Edge cases**: Test with multiple tabs, switching between tabs, and
rapid refresh scenarios
---------
Co-authored-by: Yourz <crazilou@vip.qq.com>
## Summary
Add team workspace member management and invite system.
## Changes
- Add members panel with role management (owner/admin/member) and member
removal
- Add invite system with email invites, pending invite display, and
revoke functionality
- Add invite URL loading for accepting invites
- Add subscription panel updates for member management
- Add i18n translations for member and invite features
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8245-Workspaces-4-members-invites-2f06d73d36508176b2caf852a1505c4a)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: GitHub Action <action@github.com>
Refactors modal dialog layouts for improved flexibility and consistency.
**Changes:**
- Add dedicated slot for left panel header title with dynamic
content/icons
- Consolidate side panel rendering within `BaseModalLayout`
- Remove redundant `PanelHeader` and `RightSidePanel` components
- Apply `select-none` to text elements to prevent accidental selection
---------
Co-authored-by: Amp <amp@ampcode.com>
## Summary
- Fixes remote config polling to use authenticated API
- Consolidates `loadRemoteConfig` into `refreshRemoteConfig` with auth
control
- Adds unit tests for both auth modes
## Problem
The cloud extension's polling interval was using unauthenticated
`fetch`, causing it to receive only default feature flags instead of
user-specific configurations.
**Root cause:**
1. Bootstrap called `loadRemoteConfig()` (raw `fetch`, no auth) -
correct, auth not initialized yet
2. Extension watch called `refreshRemoteConfig()` (`api.fetchApi`, with
auth) - correct
3. Extension interval called `loadRemoteConfig()` (raw `fetch`, no auth)
- **bug**
## Solution
- Consolidate into single `refreshRemoteConfig()` with optional
`useAuth` parameter (defaults to `true`)
- Bootstrap: `refreshRemoteConfig({ useAuth: false })`
- Polling: `refreshRemoteConfig()` (authenticated by default)
## Test Plan
- Unit tests verify both auth modes
- `pnpm typecheck`, `pnpm lint`, `pnpm test:unit` all pass
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8266-fix-use-authenticated-API-for-remote-config-polling-2f16d73d3650817ea7b0e3a7e3ccf12a)
by [Unito](https://www.unito.io)
## Summary
Model management improvements: refactored tag API, enhanced UX for
trigger phrases and editing.
## Changes
### API Refactor
- Add `addAssetTags` (POST) and `removeAssetTags` (DELETE) endpoints in
assetService
- `updateAssetTags` now computes diff and calls remove/add serially
- Add `TagsOperationResult` schema; cache syncs with server response
### UX Improvements
- **Trigger phrases**: click to copy individual phrases, copy-all button
in header
- **Display name**: show edit icon on hover instead of relying on
double-click
- **Model type**: show plain text when immutable instead of disabled
select
- **Tags input**: only show edit icon on hover
- **Field labels**: updated styling to use muted foreground color
- **Optimistic update** for model type selection
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Enables the feedback button on nightly releases to collect user feedback
and distinguish it from stable releases in Zendesk.
## Changes
- Add distribution tracking to feedback URL (cloud/nightly/stable)
- Export `getDistribution()` and `ZENDESK_FIELDS` from support config
for reuse
- Enable feedback button for both cloud and nightly builds
- Track distribution in Zendesk as: `ccloud`, `oss-nightly`, or `oss`
- Fix type signatures for `normalizeIndustry`/`normalizeUseCase` to
accept `unknown`
## Requirements
- [ ] Support team needs to add `oss-nightly` as a valid value for the
distribution field in Zendesk
## Test plan
- [ ] Build and run nightly version, verify feedback button appears
- [ ] Click feedback button, verify Zendesk form opens with correct
distribution parameter
- [ ] Verify cloud builds still show feedback button as before
- [ ] Verify stable OSS builds don't show feedback button
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8220-feat-enable-feedback-button-on-nightly-releases-2ef6d73d3650816db81ef970919770a4)
by [Unito](https://www.unito.io)
## Summary
Adds an editable Model Info Panel to show and modify asset details in
the asset browser.
## Changes
- Add `ModelInfoPanel` component with editable display name,
description, model type, base models, and tags
- Add `updateAssetMetadata` action in `assetsStore` with optimistic
cache updates
- Add shadcn-vue `Select` components with design system styling
- Add utility functions in `assetMetadataUtils` for extracting model
metadata
- Convert `BaseModalLayout` right panel state to `defineModel` pattern
- Add slide-in animation and collapse button for right panel
- Add `class` prop to `PropertiesAccordionItem` for custom styling
- Fix keyboard handling: Escape in TagsInput/TextArea doesn't close
parent modal
## Testing
- Unit tests for `ModelInfoPanel` component
- Unit tests for `assetMetadataUtils` functions
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Implements progressive pagination for model assets - returns the first
batch immediately while loading remaining batches in the background.
## Changes
### Store (`assetsStore.ts`)
- Adds `ModelPaginationState` tracking (assets Map, offset, hasMore,
loading, error)
- `updateModelsForKey()` returns first batch, then calls
`loadRemainingBatches()` to fetch the rest
- Accessor functions `getAssets(key)`, `isModelLoading(key)` replace
direct Map access
### API (`assetService.ts`)
- Adds `PaginationOptions` interface (`{ limit?, offset? }`)
### Components
- `AssetBrowserModal.vue` uses new accessor API
### Tests
- Updated mocks for new accessor pattern
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8212-feat-implement-progressive-pagination-for-Asset-Browser-model-assets-2ef6d73d36508157af04d1264780997e)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
## Summary
Add session download tracking to track which assets were downloaded
during the current session. This enables UI features like:
- Badge count on "Imported" nav showing newly downloaded assets
- Visual indicator on asset cards for recently downloaded items
## Changes
- Add `acknowledged` flag to `AssetDownload` interface
- Add `unacknowledgedDownloads` computed for filtering
- Add `sessionDownloadCount` computed for badge display
- Add `isDownloadedThisSession(identifier)` to check individual assets
- Add `acknowledgeDownload(identifier)` to mark assets as seen
## Testing
- 6 new unit tests covering all session tracking functionality
- Run: `pnpm test:unit -- src/stores/assetDownloadStore.test.ts`
## Related
- Part of Asset Browser improvements (#8090)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8213-feat-add-session-download-tracking-to-assetDownloadStore-2ef6d73d365081538045e8544d26bafa)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
## Summary
- Add `teamWorkspaceStore` Pinia store for workspace state management
(workspaces, members, invites, current workspace)
- Add `workspaceApi` client for workspace CRUD, member management, and
invite operations
- Update `useWorkspaceSwitch` composable for workspace switching logic
- Update `useSessionCookie` for workspace-aware sessions
- Update `firebaseAuthStore` for workspace aware auth
- Use `workspaceAuthStore` for workspace auth flow
## Test plan
- [x] 59 unit tests passing (50 store tests + 9 switch tests)
- [x] Typecheck passing
- [x] Lint passing
- [x] Knip passing
Note: This PR depends on the `team_workspaces_enabled` feature flag
being available (already in main).
🤖 Generated with [Claude Code](https://claude.ai/code)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8194-feat-add-workspace-session-auth-and-store-infrastructure-2ef6d73d3650814984afe8ee7ba0a209)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
Add `maxColumns` prop to VirtualGrid for responsive column capping.
## Changes
- **VirtualGrid**: Add `maxColumns` prop to cap grid columns; refactor
inline styles to Tailwind classes; extract spacer height computation to
helper function
- **AssetGrid**: Use `useBreakpoints` to set responsive `maxColumns`
(1-5 based on Tailwind breakpoints)
## Review Focus
- `maxColumns` behavior when `Infinity` vs finite: does
`gridTemplateColumns` override work correctly?
- Tailwind scrollbar classes replacing scoped CSS
## Summary
Fix 404 error when adding imported assets to workflow as LoadImage nodes
in Cloud mode.
## Changes
- **What**: Use `asset_hash` (hash-based filename) instead of `name`
(original filename) when creating LoadImage nodes in Cloud mode
- **Files**: `useMediaAssetActions.ts` - modified `addWorkflow` and
`addMultipleToWorkflow` functions
- **Tests**: Added `useMediaAssetActions.test.ts` with Cloud/OSS
filename selection tests
## Review Focus
- Cloud vs OSS branching logic using `isCloud && asset.asset_hash`
🤖 Generated with [Claude Code](https://claude.ai/code)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8200-bugfix-Use-asset_hash-for-LoadImage-node-in-Cloud-mode-2ef6d73d365081d785b0d7a94e73c55e)
by [Unito](https://www.unito.io)
Introduces `useFeatureUsageTracker` composable that tracks how many
times a user has used a specific feature, along with first and last
usage timestamps. Data persists to localStorage using `@vueuse/core`'s
`useStorage`. This composable provides the foundation for triggering
surveys after a configurable number of feature uses. Includes
comprehensive unit tests.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8175-feat-add-feature-usage-tracker-for-nightly-surveys-2ee6d73d36508118859ece6fcf17561d)
by [Unito](https://www.unito.io)
## Summary
Adds a compile-time `__IS_NIGHTLY__` constant that detects whether the
build is from the main branch (nightly) or a core/* branch (RC/stable).
The detection logic in vite.config.mts auto-detects based on
`GITHUB_REF_NAME === 'main'` in CI, with explicit override support via
`IS_NIGHTLY` environment variable. Exports `isNightly` from
`src/platform/distribution/types.ts` for use throughout the codebase.
Includes unit tests for the detection logic.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8149-feat-add-isNightly-build-flag-for-nightly-only-features-2ec6d73d365081c09930edec1c6644f5)
by [Unito](https://www.unito.io)