Replace dynamic MODEL_SERVICE_DEPENDENCIES injection with frozen dataclasses
(CivitAISearchDependencies, CustomUrlDependencies, ModelDetailsDependencies)
to make service dependencies explicit and type-safe. Update model services to
construct via RouteContext, and add tests enforcing minimal dataclass fields.
Break down the monolithic model_service into smaller, single-responsibility
services: CivitAISearchService, CustomUrlService, and ModelDetailsService.
Introduce ModelServiceDependencies base class to centralize RouteContext
dependency injection. Update model_service to act as a thin facade that
delegates to the specialized services. Add unit tests validating the new
service boundaries and basic request validation behavior.
Break monolithic model_info, search, and workflow route files into
smaller modules by responsibility: civitai_search, custom_url,
model_details, search_support, source_search, workflow_analysis,
hashes, and loaded_models. Update registry imports to preserve the
existing route registrations and API surface. Add partition coverage
tests to ensure no route endpoints are dropped or duplicated.
Move the inline route definitions out of __init__.py into a new core/routes
package (registry, base_models, helpers, settings, version). Add the
JobProgressTracker utility in core/progress.py and extract version discovery
logic into core/version.py. Update tests to cover the refactored structure.
Implement streaming SHA-256 verification for Python download backend,
writing to a .part file first and publishing to the final path only after
the hash matches the source metadata. Mismatched downloads are preserved
at .badsha instead of being silently deleted. Close the download response
in a finally block to avoid leaking handles on cancellation or errors.
Adds new badge, gradient, and surface variables to css-variables.css,
then uses them across resolver-main.css and resolver-shell.css to
centralize theme values and simplify future color adjustments.
Support both Comfy-Org and Kijai author indexes as known HuggingFace fallbacks, aggregate their status in the backend, refresh the cached author index, and update the frontend UI and tests.
When the resolver dialog is already visible on the Missing Models tab,
showResolvedNodeModelInResolver now reuses the existing browser instead
of forcing a reload or requeuing the selection. This avoids unnecessary
UI refreshes and keeps the current view stable.
Changes:
- web/resolver/model_resolver.js: skip reopen/queue when the dialog is
already visible on the missing tab; prefer existing browser selection
- web/resolver/views/missing_browser_methods.js: support
preferExistingBrowser in selectWorkflowModelReference and center the
selected row instead of scrolling to nearest
- tests/test_downloads_tab_workflow_route.mjs: cover reuse behavior and
row-patching/centering
- Configure callback-driven model widgets for LoRA Manager, LoraLoaderV2,
Lora Stacker, and Power Lora Loader nodes in graph and loaded graph hooks
- Track callback-driven widget states to trigger context analysis and
dialog refresh when LoRA lists or strengths change via widget callbacks
- Add signature helpers for callback-driven model list and strength changes,
including Power Lora Loader dynamic lora_N widgets
- Extend Loaded Models tab with model DOM keys, identity normalization,
copy-value updates with active/inactive grouping, and targeted strength
updates from node widgets without full re-render
- Add tests verifying callback-driven refresh behavior, suppression respect,
Power Lora Loader strength chip updates, and LoRA Manager list membership
signature tracking
Remove the brittle is-detail-collapsed responsive behavior from the missing
browser. Replace the timeout-based width handler with requestAnimationFrame
split restoration, clamp the list min width to 340px, and drop the
collapsed-state guards so the detail pane, compositor preview, and Type
column remain usable regardless of container width.
Apply the is-resizing class at resize start and remove it on end,
and raise the related resize overlay z-index so sibling content stays
visible underneath the resize indicator.