Conversation
…and tool accessibility, remove unused buttons, and enhance property bindings
…tor and reduce path serialization filesize
…ource disposal in LayeredMaskEditor and PaintCanvas
… regional prompting
… in ComfyUI, also hide civitai browser star ratings if no rating is available
Add warnings for legacy Python in InvokeAI and NVIDIA driver versions…
…eel installations & fix some issues from github
…ic, update uv, update portablegit version for windows, and enhance loading and error handling for safetensor metadata parsing
…arious view models
…oved compatibility with torch/sage/triton/nunchaku
…vice to dependency injection
Fix bugs n stuff
Introduce a new browsable Model Picker dialog with grid/list views, search, CivitAI metadata, and filter persistence. Add browse buttons to all Inference model dropdowns (Model, Refiner, VAE, Text Encoders, CLIP Vision) across ModelCard and WanModelCard. Also includes: BetterComboBox search cache invalidation on ItemsSource change, configurable search watermark, shared DetailedSearchText property on HybridModelFile, and MinDialogHeight property fix
… commands affect the clicked layer instead of currently selected layer
Apply the same fix from the previous Klein commit to the two providers Klein was cloned from. Their cancellation callbacks were spinning up a 5s timer-backed CancellationTokenSource and fire-and-forgetting it without disposing — chain a .ContinueWith(Dispose) onto the interrupt task so the timer cleans up after the request settles. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ux2-klein Image Lab polish + Flux.2 Klein + ComfyUI folder types + scrollbar UX
shoutout chagenlog
Replaces the bundled 7-Zip executables on all three platforms with the official 26.01 release (2026-04-27) from the ip7z/7zip GitHub releases. 26.01 includes the fix for the NTFS heap buffer overflow CVE-2026-48095 (GitHub Security Lab GHSL-2026-140, CVSS 8.8) and brings years of accumulated upstream security fixes. The Windows 7za.exe had been pinned at the 2018-era 18.01 release; Linux/macOS were on ~23.01. - StabilityMatrix.Avalonia/Assets/win-x64/7za.exe 18.01 -> 26.01 - StabilityMatrix.Avalonia/Assets/linux-x64/7zzs ~23.01 -> 26.01 - StabilityMatrix.Avalonia/Assets/macos-arm64/7zz ~23.01 -> 26.01 - StabilityMatrix/Assets/7za.exe (legacy WPF) 18.01 -> 26.01 License files updated to the 26.01 text. Binary architectures match the originals exactly (Windows PE32+ x64, Linux static ELF x64, macOS universal x86_64+arm64). The 7za command-line surface used by ArchiveHelper (a/t/x/-o/-y/-bsp1) is unchanged, so this is a drop-in replacement requiring no code changes; verified with an add/test/extract round-trip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…026-48095 Update bundled 7-Zip to 26.01 (CVE-2026-48095)
The 7-Zip binary runs from <DataDir>/Assets, which is only re-unpacked from the app bundle during a package *install* (SetupPrerequisitesStep -> UnpackResourcesIfNecessary). Package *updates* and app updates never refresh it, so an existing install could keep a stale binary (e.g. the old 18.01 with CVE-2026-48095) indefinitely if the user only ever updated existing packages. Add a version-stamped refresh at startup: compare a new Settings.LastUnpacked7zVersion against the bundled Assets.SevenZipVersion constant in MainWindowViewModel.OnInitialLoadedAsync (after the data directory is ensured). On mismatch, re-unpack the resources and update the stamp. It's a cheap string compare on every launch and only does I/O the first launch after a version bump. Failures are logged but non-fatal since the install/update flows still re-unpack on demand. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
MainWindowViewModel now takes IPrerequisiteHelper, and its design-time factory resolves it via GetRequiredService. DesignData registered IPrerequisiteHelper as `_ => null!` in the "placeholder" block, which returns null from GetService — and GetRequiredService can't distinguish "registered but null" from "not registered", so it threw "No service for type IPrerequisiteHelper has been registered" and broke DesignDataTests.Property_ShouldBeNotNull. Register it as a real NSubstitute mock alongside the other mock services instead of the null placeholder. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
remove unnecessary info from chagenlog
The version-stamped 7-Zip refresh previously ran before the single-instance check, so two instances launched simultaneously could both reach the unpack and race on writing the binary before the loser shut down. Move it to just after the instance guard so only the surviving instance ever writes 7za.exe. It still runs before any 7z consumer (downloads are only listed/started later in this method, install dialogs come after), so the write never races with an extraction either. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the startup version-stamped refresh with a SetupPrerequisitesStep in the package update flow. Per discussion, the bundled 7z is never run on attacker-controlled input (the only auto-extracted download is a first-party, hash-verified zip; the model browser downloads raw files), so the startup unpack was disproportionate and risked AV false-positives for writing an exe on launch. Instead, the package Update and ChangeVersion flows now run the same SetupPrerequisitesStep that installs use, which calls UnpackResourcesIfNecessary and refreshes the on-disk binary. Previously those flows ran only UpdatePackageStep, so an updated package kept whatever 7z binary was already on disk. Reverts the startup hook: MainWindowViewModel IPrerequisiteHelper injection + refresh block, the App factory arg, Assets.SevenZipVersion, and Settings.LastUnpacked7zVersion. Keeps the DesignData IPrerequisiteHelper mock registration since PackageCardViewModel now depends on it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…-startup Refresh bundled 7-Zip on package update (not startup)
Downmerg from public
Downmerg from main
Documents the Windows ROCm work from LykosAI#1629 (by @NeuralFault): - Added: expanded native Windows ROCm GPU coverage (Vega/GCN5 through RDNA4) via a shared helper now used by ComfyUI, SwarmUI, reForge, InvokeAI, and Wan2GP; plus optional ROCm package commands (SageAttention, Flash Attention, bitsandbytes, ROCm SDK devel). - Changed: PyTorch TunableOp now disabled by default, with a note on re-enabling via PYTORCH_TUNABLEOP_ENABLED=1. - Fixed: user-set env vars not overriding package-configured ROCm vars; pip show "not found" being raised as an exception instead of treated as a missing-package state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add v2.16.0-pre.2 changelog entries for AMD/ROCm support (LykosAI#1629)
…bilityMatrix into mega-chagenlog-2-16
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
shoutout n mega chagenlog
Dev to main
There was a problem hiding this comment.
Code Review
This pull request introduces the new 'Image Lab' conversational image generation interface, a CivArchive model browser, a checkpoint organizer, and video thumbnail generation using FFmpeg, alongside UI enhancements like fuzzy search in BetterComboBox. The code review highlighted several critical issues, including compilation errors in PaintCanvas.axaml.cs (calling Dispose on non-disposable Cursor objects) and PngDataHelper.cs (referencing an undefined variable). Additionally, the reviewer noted a missing FFmpeg download URL for Intel Macs, a lifecycle bug in BetterComboBox that breaks event handling upon detachment, potential overflow crashes in PenPointJsonConverter with negative coordinates, a circular dependency risk in NotificationService, and missing cancellation or race-condition guards in VideoThumbnailService and CivArchiveDetailsPageViewModel.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| public static RemoteResource FfmpegDownloadUrl => | ||
| Compat.Switch( | ||
| ( | ||
| PlatformKind.Windows | PlatformKind.X64, | ||
| new RemoteResource | ||
| { | ||
| // BtbN LGPL build - ffmpeg-n7.1-latest-win64-lgpl-7.1 | ||
| Url = new Uri( | ||
| "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n7.1-latest-win64-lgpl-7.1.zip" | ||
| ), | ||
| HashSha256 = "a77ecdc794d67401f3e4976f8856065f7762d74afd16f9c7b777ff0291a7bcaa", | ||
| } | ||
| ), | ||
| ( | ||
| PlatformKind.Linux | PlatformKind.X64, | ||
| new RemoteResource | ||
| { | ||
| // BtbN LGPL build - linux | ||
| Url = new Uri( | ||
| "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n7.1-latest-linux64-lgpl-7.1.tar.xz" | ||
| ), | ||
| HashSha256 = "d7d691dfa3a6d0a75362c02274a80a1f9635bd67908561aae31ee538853ab8ce", | ||
| } | ||
| ), | ||
| ( | ||
| PlatformKind.MacOS | PlatformKind.Arm, | ||
| new RemoteResource | ||
| { | ||
| // evermeet.cx build for macOS arm64 | ||
| Url = new Uri("https://evermeet.cx/ffmpeg/ffmpeg-7.1.1.zip"), | ||
| HashSha256 = "8d7917c1cebd7a29e68c0a0a6cc4ecc3fe05c7fffed958636c7018b319afdda4", | ||
| } | ||
| ) | ||
| ); |
There was a problem hiding this comment.
The FfmpegDownloadUrl property is missing an entry for PlatformKind.MacOS | PlatformKind.X64 (Intel Macs). If an Intel Mac user runs the application, Compat.Switch will fail to find a matching platform and throw an exception or fail to download FFmpeg, breaking video thumbnail generation. Please add a fallback or an explicit entry for Intel Macs.
(
PlatformKind.MacOS | PlatformKind.X64,
new RemoteResource
{
// evermeet.cx build for macOS x64
Url = new Uri("https://evermeet.cx/ffmpeg/ffmpeg-7.1.1.zip"),
HashSha256 = "8d7917c1cebd7a29e68c0a0a6cc4ecc3fe05c7fffed958636c7018b319afdda4", // Replace with correct x64 hash
}
)| protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) | ||
| { | ||
| base.OnDetachedFromVisualTree(e); | ||
|
|
||
| DropDownOpened -= OnDropDownOpened; | ||
| DropDownClosed -= OnDropDownClosed; | ||
| ContainerPrepared -= OnContainerPrepared; | ||
| ContainerIndexChanged -= OnContainerIndexChanged; | ||
|
|
There was a problem hiding this comment.
In OnDetachedFromVisualTree, the control unsubscribes from its own events (DropDownOpened, DropDownClosed, ContainerPrepared, ContainerIndexChanged) which were subscribed in the constructor. Since there is no OnAttachedToVisualTree override to re-subscribe them, the ComboBox will completely lose its search/filtering functionality if it is ever detached and re-attached to the visual tree (which is common when switching tabs or recycling views). Since these are events on this (the control itself), they do not cause memory leaks and do not need to be unsubscribed. Please remove these unsubscriptions, or move both subscription and unsubscription to OnAttachedToVisualTree and OnDetachedFromVisualTree respectively.
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnDetachedFromVisualTree(e);
if (searchTextBox is not null)
{
searchTextBox.TextChanged -= SearchTextBoxOnTextChanged;
searchTextBox.KeyDown -= SearchTextBoxOnKeyDown;
}
if (settingsManager is not null)
{
settingsManager.SettingsPropertyChanged -= OnSettingsPropertyChanged;
}
legacySearchResetTimer.Tick -= OnLegacySearchResetTimerTick;
StopLegacySearchResetTimer();
HideLegacySearchPopup();
subscription.Dispose();
}| if (lastCanvasCursorTool != selectedTool) | ||
| { | ||
| lastCanvasCursor?.Dispose(); | ||
| lastCanvasCursor = new Cursor(StandardCursorType.Cross); | ||
| lastCanvasCursorTool = selectedTool; |
There was a problem hiding this comment.
lastCanvasCursor?.Dispose(); is called on lastCanvasCursor which is of type Avalonia.Input.Cursor. However, Cursor in Avalonia does not implement IDisposable, so this will cause a compilation error. Please remove the Dispose() call.
if (lastCanvasCursorTool != selectedTool)
{
lastCanvasCursor = new Cursor(StandardCursorType.Cross);
lastCanvasCursorTool = selectedTool;
}| if (lastCanvasCursorTool != selectedTool) | ||
| { | ||
| lastCanvasCursor?.Dispose(); | ||
| lastCanvasCursor = new Cursor(StandardCursorType.SizeAll); | ||
| lastCanvasCursorTool = selectedTool; |
There was a problem hiding this comment.
lastCanvasCursor?.Dispose(); is called on lastCanvasCursor which is of type Avalonia.Input.Cursor. However, Cursor in Avalonia does not implement IDisposable, so this will cause a compilation error. Please remove the Dispose() call.
if (lastCanvasCursorTool != selectedTool)
{
lastCanvasCursor = new Cursor(StandardCursorType.SizeAll);
lastCanvasCursorTool = selectedTool;
}| InferenceProjectDocument projectDocument | ||
| ) | ||
| { | ||
| // Validate PNG header | ||
| if (inputImage.Length < 8 || !inputImage[..8].AsSpan().SequenceEqual(PngHeader)) | ||
| { | ||
| Logger.Warn( | ||
| "AddMetadata: Image data ({Size} bytes) does not have a valid PNG header, " | ||
| + "the file may not actually be a PNG. Returning image as-is", | ||
| inputImage.Length | ||
| ); | ||
| return inputImage; | ||
| } |
There was a problem hiding this comment.
In AddMetadata, the PNG header validation uses inputImage.Length and inputImage[..8], but inputImage is not a parameter of AddMetadata (the parameter is Stream inputStream), and inputImage is not defined at the start of the method. This will cause a compilation error. You should perform this validation after reading the stream into a byte array, or read the first 8 bytes from inputStream to validate the header before processing.
public static byte[] AddMetadata(
Stream inputStream,
InferenceProjectDocument projectDocument
)
{
using var memoryStream = new MemoryStream();
inputStream.CopyTo(memoryStream);
var inputImage = memoryStream.ToArray();
// Validate PNG header
if (inputImage.Length < 8 || !inputImage[..8].AsSpan().SequenceEqual(PngHeader))
{
Logger.Warn(
"AddMetadata: Image data ({Size} bytes) does not have a valid PNG header, "
+ "the file may not actually be a PNG. Returning image as-is",
inputImage.Length
);
return inputImage;
}
memoryStream.SetLength(0); // Clear the stream to reuse it for writing
var position = 8; // Skip the PNG signature
memoryStream.Write(inputImage, 0, position);
var metadataInserted = false;| if (reader.TryGetUInt64(out var ulongX)) | ||
| x = ulongX; | ||
| else if (reader.TryGetDouble(out var doubleX)) | ||
| x = Convert.ToUInt64(doubleX); | ||
| } |
There was a problem hiding this comment.
In PenPointJsonConverter.Read, Convert.ToUInt64(doubleX) is used to convert a double to ulong. If the legacy JSON contains negative coordinates (which can happen due to offsets, drag coordinates, or window scaling), Convert.ToUInt64 will throw an OverflowException, crashing the deserialization process. A safer cast with bounds checking should be used instead.
if (reader.TryGetUInt64(out var ulongX))
x = ulongX;
else if (reader.TryGetDouble(out var doubleX))
x = doubleX >= 0 && doubleX <= ulong.MaxValue ? (ulong)doubleX : 0;| if (reader.TryGetUInt64(out var ulongY)) | ||
| y = ulongY; | ||
| else if (reader.TryGetDouble(out var doubleY)) | ||
| y = Convert.ToUInt64(doubleY); | ||
| } |
There was a problem hiding this comment.
In PenPointJsonConverter.Read, Convert.ToUInt64(doubleY) is used to convert a double to ulong. If the legacy JSON contains negative coordinates, Convert.ToUInt64 will throw an OverflowException, crashing the deserialization process. A safer cast with bounds checking should be used instead.
if (reader.TryGetUInt64(out var ulongY))
y = ulongY;
else if (reader.TryGetDouble(out var doubleY))
y = doubleY >= 0 && doubleY <= ulong.MaxValue ? (ulong)doubleY : 0;| public class NotificationService( | ||
| ILogger<NotificationService> logger, | ||
| ISettingsManager settingsManager, | ||
| INotificationHistoryService historyService, | ||
| INotificationActionDispatcher actionDispatcher | ||
| ) : INotificationService, IDisposable |
There was a problem hiding this comment.
Injecting INotificationActionDispatcher directly into the NotificationService constructor can easily lead to circular dependencies. NotificationService is a core singleton used by almost all view models, while NotificationActionDispatcher depends on INavigationService<MainWindowViewModel>, which in turn instantiates MainWindowViewModel and its page view models (which inject INotificationService). To prevent startup circular dependency exceptions, resolve actionDispatcher lazily using IServiceProvider or Lazy<INotificationActionDispatcher> when dispatching actions.
public class NotificationService(
ILogger<NotificationService> logger,
ISettingsManager settingsManager,
INotificationHistoryService historyService,
IServiceProvider serviceProvider
) : INotificationService, IDisposable| var result = await ProcessRunner | ||
| .GetProcessResultAsync(ffmpegPath, args.ToProcessArgs()) | ||
| .ConfigureAwait(false); | ||
|
|
There was a problem hiding this comment.
In GenerateThumbnailAsync, ProcessRunner.GetProcessResultAsync is called without passing the cancellationToken. If the user cancels the operation (e.g., navigates away or closes the app), the FFmpeg process will continue running in the background. Please pass cancellationToken to GetProcessResultAsync to ensure the process is terminated upon cancellation.
var result = await ProcessRunner
.GetProcessResultAsync(ffmpegPath, args.ToProcessArgs(), cancellationToken)
.ConfigureAwait(false)|
|
||
| IsInstalled = true; | ||
| _ = LoadInstalledLocationAsync(matchedHash); |
There was a problem hiding this comment.
_ = LoadInstalledLocationAsync(matchedHash); is called as a fire-and-forget task. If the user switches versions quickly, multiple concurrent loads can run, leading to a race condition where a slower, older request overwrites InstalledLocation with a stale value. Please use a CancellationToken or track the latest task to discard stale results.
Added
New Feature: 🧪 Image Lab - Conversational Image Generation for ComfyUI
Flux2Schedulerfor Flux.2) are wired up automatically across Text-to-Image and Image-to-Imageres_multistep/simple/ 8 steps / CFG 1 for Z-Image Turbo,er_sde/simple/ 30 steps / CFG 4 for Anima,euler/ 20 steps / CFG 5 for Flux.2sd3encoder)12.3K · artistso the more common tags are easier to spot at a glanceer_sdeandres_multistepto the Inference sampler liststable_diffusion,flux2, andlumina2Encoder Type options for UNet workflows--bnb) inferencestyle_models,audio_encoders,model_patches, andbackground_removaldirectories. Models in these folders are now indexed and symlinked alongside everything else (e.g. Flux Redux / B-Lora style models, audio encoders for video/audio workflows, BiRefNet background-removal models)Changed
Fixed
transformersversion — installs now pintransformers==4.54.1and exclude it from the default requirements passinference/gradio_composite_demodirectory when the parent path didn't already existFile not found: venv/uv-build-constraints.txtby no longer leaking the relative build-constraints path into the running package's environmentDisplay controller-class integrated GPUs not appearing in the GPU list on Linuxsitecustomize.pyor its compiled bytecode was corrupted by external software (e.g. some antivirus suites); the file now self-heals when out of date and its startup actions can no longer abort interpreter startup$#1234andcivitai.com/models/1234URL searches returning zero results for some models that exist and are downloadable on the website — the app now retries via a per-model lookup when the batch search misses a requested ID$#1234searches with non-LORA / non-Checkpoint targets returning no results when the Model Type dropdown wasn't set to All — ID searches intentionally bypass the type and base-model filters in the request, but the post-response check was still rejecting the returned model when its type didn't match the dropdownSecurity
Supporters
🌟 Visionaries
An enormous thank you to our incredible Visionaries: Waterclouds, bluepopsicle, Ibixat, Droolguy, snotty, LG, whudunit, MrMxyzptlk12836, Psilocyfer18731, KalAbaddon, and moon_milky2843! This was a huge release, and every bit of it rests on your generosity. Whether you've been cheering us on for years or only just joined, having you in our corner is what makes all of this possible. We're so grateful for you. 💛
🚀 Pioneers
And what a Pioneer crew this release! A heartfelt thank you to the regulars who keep showing up for us: Szir777, [USA]TechDude, SinthCore, Jisuren, Tigon, jweg79, rwx14662, Hurbie53, ahnhj.al, drew.lukas, Tuskaruho, Cjloha, Alligator1907, Bitti, damianpointdexter, Ghislain G, and tmdcks! Your steady support release after release is what keeps us at the keyboard. And the warmest of welcomes to our newest Pioneers: CommissarGiygas16050, qob97515211, bastardofbethlehem, and Zombop — we're thrilled you've joined us, and we can't wait to get to know you! (And to our anonymous Pioneer out there too — our thanks reaches you. 💛)