Conversation
This comment has been minimized.
This comment has been minimized.
|
Warning Review limit reached
More reviews will be available in 53 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR adds a DI-backed WPF relay shell, layered configuration and logging infrastructure, updated relay service lifecycle and radio state handling, shared UI controls/converters, and new About, Configuration, Devices, Logs, and Operations pages. ChangesDesktop shell and relay flow
Estimated code review effort🎯 5 (Critical) | ⏱️ ~90+ minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 15
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Resgrid.Audio.Core/WatcherAudioStorage.cs (1)
19-26: 🩺 Stability & Availability | 🟡 MinorStatic
_watcherAudiois safe under current deployment model.
WatcherAudioStorageis instantiated directly vianew WatcherAudioStorage(logger)inResgrid.Audio.Relay.Console/Program.cs, not registered in the DI container. The application runs as a single-process relay creating exactly one instance per lifecycle, preventing the static dictionary reset conflict described.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Resgrid.Audio.Core/WatcherAudioStorage.cs` around lines 19 - 26, The concern is the static `_watcherAudio` field in `WatcherAudioStorage`, but this class is created once directly from `Program` and not through DI, so the current singleton-like lifecycle is safe. Keep `_watcherAudio` as static and initialized in the `WatcherAudioStorage(ILogger logger)` constructor; no scoped-instance refactor is needed. If you want to make the assumption clearer, add a brief note near the field or constructor referencing the single-instance relay lifecycle used by `Program`.
🧹 Nitpick comments (3)
Resgrid.Audio.Relay/ShellWindow.xaml.cs (1)
143-146: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueSilent VM-less fallback in
GetPagemasks DI misconfiguration.When a page type isn't registered,
_provider.GetService(pageType)returns null and the code falls back toActivator.CreateInstance(pageType). For these views the parameterless constructor runsInitializeComponent()but never setsDataContext/_viewModel, so the user silently gets a blank, non-functional page instead of a clear failure. Consider failing fast (or logging) so a missing registration surfaces during development.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Resgrid.Audio.Relay/ShellWindow.xaml.cs` around lines 143 - 146, The GetPage fallback is silently creating pages without DI when a type is not registered, which hides configuration errors and can leave views without a DataContext or _viewModel; update GetPage in ShellWindow.xaml.cs to fail fast or explicitly log when _provider.GetService(pageType) returns null instead of always falling back to Activator.CreateInstance(pageType), so missing registrations surface immediately during development.Resgrid.Audio.Relay/Views/DevicesView.xaml.cs (1)
6-6: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueStale doc comment. The XML summary still calls this a "Placeholder Devices screen — filled in by the next UI pass," but the view and its bindings are now implemented. Update the comment to avoid confusion.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Resgrid.Audio.Relay/Views/DevicesView.xaml.cs` at line 6, The XML summary on DevicesView is stale and still describes the view as a placeholder even though the bindings and UI are implemented. Update the summary comment in DevicesView.xaml.cs to reflect the actual purpose of the DevicesView class, keeping it accurate and concise so it matches the current implementation.Resgrid.Audio.Relay/Converters/BoolToVisibilityConverter.cs (1)
15-17: 📐 Maintainability & Code Quality | 🔵 TrivialImmutable shared singleton instance.
Resgrid.Audio.Relay.csprojtargetsnet10.0-windows, which fully supportsinitaccessors. BecauseInstanceis a shared static resource, theInvertproperty should be set once and never mutated across the app. Change the accessor toget; init;to prevent unintended state changes if a consumer reuses the shared instance.Refactor
- public bool Invert { get; set; } + public bool Invert { get; init; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@Resgrid.Audio.Relay/Converters/BoolToVisibilityConverter.cs` around lines 15 - 17, The shared singleton in BoolToVisibilityConverter should be immutable so its state cannot be changed after initialization. Update the Invert property on BoolToVisibilityConverter to use an init-only accessor instead of a set accessor, keeping Instance as the shared static entry point and preventing later mutation from consumers that reuse it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Resgrid.Audio.Relay/App.xaml.cs`:
- Around line 82-89: The logging setup in App.xaml.cs is inconsistent with its
comment because the LoggerConfiguration in the logger initialization only uses
WriteTo.UiBus(logBus) and does not include a Debug sink. Update the
implementation to match the intended behavior by either adding the missing
WriteTo.Debug() sink in the LoggerConfiguration chain or removing the “plus
Debug for local diagnostics” wording from the comment so it accurately reflects
the actual sinks configured.
In `@Resgrid.Audio.Relay/Controls/LevelMeter.xaml.cs`:
- Around line 37-42: Update LevelMeter.xaml.cs so UpdateVisual uses the same
clamped value for both the bar and the label. Right now Bar.Value is based on
the clamped percentage, but Label.Text still formats the raw db input; change
the label to display the clamped dBFS value derived in UpdateVisual (or a shared
clamped variable) so the UI stays consistent with the -80..0 range comment.
In `@Resgrid.Audio.Relay/Controls/Sparkline.cs`:
- Around line 90-107: The Sparkline control only detaches from the previous
Values collection in OnValuesChanged, so it can stay subscribed after the view
is unloaded and leak via OnValuesCollectionChanged. Update Sparkline to
unsubscribe from the current INotifyCollectionChanged when the control is
unloaded/disposed, and re-subscribe when it is loaded again if needed. Use the
existing OnValuesChanged and OnValuesCollectionChanged hooks to centralize the
attach/detach logic so the control stops receiving CollectionChanged events once
it is no longer on screen.
In `@Resgrid.Audio.Relay/Controls/StatusPill.xaml`:
- Around line 13-21: The StatusPill control currently renders only the static
Label via the TextBlock in StatusPill.xaml, so the visual state is communicated
only by the background brush. Update the StatusPill template and its Root
bindings so the displayed text includes the actual State value (or a
state-derived label) alongside the existing Label, keeping DashboardView callers
like API and LiveKit unchanged. Make the text content in the StatusPill control
reflect both the label and connection state so screen readers and non-color
users can perceive status without relying on the brush alone.
In `@Resgrid.Audio.Relay/Resgrid.Audio.Relay.csproj`:
- Line 24: The NAudio dependency version in
Resgrid.Audio.Relay/Resgrid.Audio.Core is out of sync with the checked-in
DtmfDetection.NAudio binary. Verify DtmfDetection.NAudio.dll is compatible with
NAudio 1.10.0; if not, rebuild or replace the binary so it matches the current
NAudio package version. Update the references in Resgrid.Audio.Core and any
related project settings so the DtmfDetection path and NAudio PackageReference
stay aligned.
In `@Resgrid.Audio.Relay/Services/RelayController.cs`:
- Around line 97-118: The race is in RelayController when the entry is added to
_entries before Entry.RunTask is initialized, allowing StopAsync to see a
partially published entry. Update the Start/launch path so the background task
is created first and the entry is fully initialized before publication, or make
the _entries insert and RunTask assignment happen atomically under _gate; use
RelayController, Entry.RunTask, and the StartAsync/task-launch block to locate
the fix.
- Around line 30-35: `RelayController` is still using
`SynchronizationContext.Current` and can end up posting `RunningServices`
updates on the caller thread when the context is null. Update `RelayController`
to marshal through `Application.Current.Dispatcher` instead of `_uiContext`, and
adjust the `Post`/collection-update path so every UI-bound change is invoked on
the UI thread. Keep the change centered around `RelayController` and the
`ServiceTileViewModel`-triggered update flow so the dispatcher is used
consistently.
In `@Resgrid.Audio.Relay/ViewModels/ConfigurationViewModel.cs`:
- Around line 512-514: The tuning path in ConfigurationViewModel is mutating the
shared live configuration instead of a temporary snapshot. Update the code
around ApplyToOptions so it operates on an isolated copy of the current
settings, not _configuration.Current, and only uses the edited Radio values
needed for tuning. Make sure the tuner gets a cloned or disk-loaded options
instance while leaving the shared Current object untouched so uncommitted form
changes do not affect active services like RelayController.
In `@Resgrid.Audio.Relay/ViewModels/ModeCardViewModel.cs`:
- Around line 61-76: Update ModeCardViewModel so the Start button is disabled
when pre-flight validation has already failed. The current CanStart() only
checks IsRunning, so include HasValidationErrors in that predicate (alongside
!IsRunning) and keep notifying the StartCommand state after validation changes.
Use the ModeCardViewModel.CanStart method and the HasValidationErrors flag to
locate the fix, and ensure the UI state matches OperationsViewModel.StartMode
behavior.
In `@Resgrid.Audio.Relay/ViewModels/OperationsViewModel.cs`:
- Around line 64-95: StartMode currently relies on IsRunning/FindRunning, which
only read RelayController.RunningServices and miss the async gap before
RunningServices.Add is posted from Start. Update OperationsViewModel so the
duplicate-start check uses authoritative controller state from RelayController
(or add a local pending-start guard in StartMode) instead of the delayed UI
collection, and keep the validation short-circuit behavior intact.
In `@Resgrid.Audio.Relay/Views/AboutView.xaml.cs`:
- Line 6: The summary on AboutView is stale and still describes the view as a
placeholder even though the page is implemented. Update or remove the XML doc
comment on AboutView in AboutView.xaml.cs so it accurately reflects the current
behavior and features exposed by the view, keeping the description aligned with
the actual UI instead of the old placeholder wording.
In `@Resgrid.Audio.Relay/Views/LogsView.xaml.cs`:
- Around line 39-49: The `OnUnloaded` cleanup in `LogsView` is disposing and
nulling `_viewModel`, which breaks the page when WPF `Frame` back-navigation
reuses the same view instance. Update `OnUnloaded` to only detach
`EntriesAppended` and avoid calling `Dispose()` or clearing `_viewModel` unless
the view is truly being destroyed; if reuse is expected,
reinitialize/re-subscribe in `OnLoaded`/`OnNavigatedTo` so the pump and handler
are restored when the page comes back.
In `@Resgrid.Relay.Engine/Services/RelayServiceBase.cs`:
- Around line 77-81: The startup flow in RelayServiceBase.StartAsync can
overwrite a concurrent StopAsync state change by transitioning to Running
unconditionally before ExecuteAsync begins. Update the Running transition in
StartAsync to only occur when the service is still in Starting, or when the
startup token has not already been canceled by StopAsync, so a stop that wins
the startup race keeps the service in Stopping/Stopped instead of being reverted
to Running. Use the existing TransitionTo, _state, _cts, and ExecuteAsync
symbols to place the guard at the point where the running state is published.
In `@Resgrid.Relay.Engine/Services/RelayServiceFactory.cs`:
- Line 20: The RelayServiceFactory mode selection is silently defaulting
whitespace-only values to smtp, which should be treated as a configuration error
instead. Update the mode resolution in RelayServiceFactory so only a null
options.Mode falls back to the default, while trimmed-empty or whitespace-only
values are rejected explicitly before any relay is created; use the existing
mode-handling logic in RelayServiceFactory to keep the validation centralized.
In `@Resgrid.Relay.Engine/Voice/DispatchVoiceMode.cs`:
- Around line 57-61: The TTS state in DispatchVoiceMode is left at Unknown after
repeated announcement failures, so the per-call failure path never reflects that
the service is unreachable. Update the AnnounceAsync exception handling in
DispatchVoiceMode to set status.Tts to Disconnected before the next retry/poll,
while keeping the existing Unknown on first probe and Connected on successful
announcement flow.
---
Outside diff comments:
In `@Resgrid.Audio.Core/WatcherAudioStorage.cs`:
- Around line 19-26: The concern is the static `_watcherAudio` field in
`WatcherAudioStorage`, but this class is created once directly from `Program`
and not through DI, so the current singleton-like lifecycle is safe. Keep
`_watcherAudio` as static and initialized in the `WatcherAudioStorage(ILogger
logger)` constructor; no scoped-instance refactor is needed. If you want to make
the assumption clearer, add a brief note near the field or constructor
referencing the single-instance relay lifecycle used by `Program`.
---
Nitpick comments:
In `@Resgrid.Audio.Relay/Converters/BoolToVisibilityConverter.cs`:
- Around line 15-17: The shared singleton in BoolToVisibilityConverter should be
immutable so its state cannot be changed after initialization. Update the Invert
property on BoolToVisibilityConverter to use an init-only accessor instead of a
set accessor, keeping Instance as the shared static entry point and preventing
later mutation from consumers that reuse it.
In `@Resgrid.Audio.Relay/ShellWindow.xaml.cs`:
- Around line 143-146: The GetPage fallback is silently creating pages without
DI when a type is not registered, which hides configuration errors and can leave
views without a DataContext or _viewModel; update GetPage in ShellWindow.xaml.cs
to fail fast or explicitly log when _provider.GetService(pageType) returns null
instead of always falling back to Activator.CreateInstance(pageType), so missing
registrations surface immediately during development.
In `@Resgrid.Audio.Relay/Views/DevicesView.xaml.cs`:
- Line 6: The XML summary on DevicesView is stale and still describes the view
as a placeholder even though the bindings and UI are implemented. Update the
summary comment in DevicesView.xaml.cs to reflect the actual purpose of the
DevicesView class, keeping it accurate and concise so it matches the current
implementation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 89e8d375-70c6-4187-ac9c-594e4cada608
📒 Files selected for processing (75)
Directory.Build.propsResgrid.Audio.Core/AudioEvaluator.csResgrid.Audio.Core/Radio/RadioBridge.csResgrid.Audio.Core/WatcherAudioStorage.csResgrid.Audio.Relay/App.xamlResgrid.Audio.Relay/App.xaml.csResgrid.Audio.Relay/Controls/LevelMeter.xamlResgrid.Audio.Relay/Controls/LevelMeter.xaml.csResgrid.Audio.Relay/Controls/Sparkline.csResgrid.Audio.Relay/Controls/StatusPill.xamlResgrid.Audio.Relay/Controls/StatusPill.xaml.csResgrid.Audio.Relay/Converters/BoolToBrushConverter.csResgrid.Audio.Relay/Converters/BoolToVisibilityConverter.csResgrid.Audio.Relay/Converters/BoolToVisibilityInvertedConverter.csResgrid.Audio.Relay/Converters/ConnectionStateToBrushConverter.csResgrid.Audio.Relay/Converters/CountToVisibilityConverter.csResgrid.Audio.Relay/Converters/LogLevelToBrushConverter.csResgrid.Audio.Relay/Converters/RelayServiceStateToBrushConverter.csResgrid.Audio.Relay/Converters/SecretMaskConverter.csResgrid.Audio.Relay/Converters/SquelchTextConverter.csResgrid.Audio.Relay/Converters/StatusBrushes.csResgrid.Audio.Relay/Converters/TuneButtonTextConverter.csResgrid.Audio.Relay/MainWindow.xamlResgrid.Audio.Relay/MainWindow.xaml.csResgrid.Audio.Relay/Properties/Resources.Designer.csResgrid.Audio.Relay/Properties/Resources.resxResgrid.Audio.Relay/Properties/Settings.Designer.csResgrid.Audio.Relay/Properties/Settings.settingsResgrid.Audio.Relay/Resgrid.Audio.Relay.csprojResgrid.Audio.Relay/Resources/AppDictionary.xamlResgrid.Audio.Relay/Services/ConfigurationService.csResgrid.Audio.Relay/Services/DeviceEnumerationService.csResgrid.Audio.Relay/Services/RelayController.csResgrid.Audio.Relay/ShellWindow.xamlResgrid.Audio.Relay/ShellWindow.xaml.csResgrid.Audio.Relay/Skins/MainSkin.xamlResgrid.Audio.Relay/ViewModel/MainWindowViewModel.csResgrid.Audio.Relay/ViewModel/ShuttingDownMessage.csResgrid.Audio.Relay/ViewModel/ViewModelLocator.csResgrid.Audio.Relay/ViewModels/AboutViewModel.csResgrid.Audio.Relay/ViewModels/ConfigurationViewModel.csResgrid.Audio.Relay/ViewModels/DashboardViewModel.csResgrid.Audio.Relay/ViewModels/DevicesViewModel.csResgrid.Audio.Relay/ViewModels/LogsViewModel.csResgrid.Audio.Relay/ViewModels/ModeCardViewModel.csResgrid.Audio.Relay/ViewModels/OperationsViewModel.csResgrid.Audio.Relay/ViewModels/ServiceTileViewModel.csResgrid.Audio.Relay/ViewModels/ShellViewModel.csResgrid.Audio.Relay/Views/AboutView.xamlResgrid.Audio.Relay/Views/AboutView.xaml.csResgrid.Audio.Relay/Views/ConfigurationView.xamlResgrid.Audio.Relay/Views/ConfigurationView.xaml.csResgrid.Audio.Relay/Views/DashboardView.xamlResgrid.Audio.Relay/Views/DashboardView.xaml.csResgrid.Audio.Relay/Views/DevicesView.xamlResgrid.Audio.Relay/Views/DevicesView.xaml.csResgrid.Audio.Relay/Views/LogsView.xamlResgrid.Audio.Relay/Views/LogsView.xaml.csResgrid.Audio.Relay/Views/OperationsView.xamlResgrid.Audio.Relay/Views/OperationsView.xaml.csResgrid.Relay.Engine/Configuration/RelayConfiguration.csResgrid.Relay.Engine/Logging/LogRecord.csResgrid.Relay.Engine/Logging/UiBusSinkExtensions.csResgrid.Relay.Engine/Logging/UiLogBus.csResgrid.Relay.Engine/Logging/UiLogSink.csResgrid.Relay.Engine/Services/AudioImportService.csResgrid.Relay.Engine/Services/DispatchRelayService.csResgrid.Relay.Engine/Services/RadioRelayService.csResgrid.Relay.Engine/Services/RecordRelayService.csResgrid.Relay.Engine/Services/RelayServiceBase.csResgrid.Relay.Engine/Services/RelayServiceFactory.csResgrid.Relay.Engine/Services/SmtpRelayService.csResgrid.Relay.Engine/Voice/AudioImportMode.csResgrid.Relay.Engine/Voice/DispatchVoiceMode.csResgrid.Relay.Engine/Voice/RadioMode.cs
💤 Files with no reviewable changes (11)
- Resgrid.Audio.Relay/Properties/Settings.settings
- Resgrid.Audio.Relay/ViewModel/MainWindowViewModel.cs
- Resgrid.Audio.Relay/ViewModel/ViewModelLocator.cs
- Resgrid.Audio.Relay/Resources/AppDictionary.xaml
- Resgrid.Audio.Relay/Skins/MainSkin.xaml
- Resgrid.Audio.Relay/ViewModel/ShuttingDownMessage.cs
- Resgrid.Audio.Relay/Properties/Resources.Designer.cs
- Resgrid.Audio.Relay/MainWindow.xaml
- Resgrid.Audio.Relay/Properties/Settings.Designer.cs
- Resgrid.Audio.Relay/Properties/Resources.resx
- Resgrid.Audio.Relay/MainWindow.xaml.cs
| // UI log bus + a Serilog logger fanned out to it (plus Debug for local diagnostics). | ||
| var logBus = new UiLogBus(); | ||
| services.AddSingleton(logBus); | ||
|
|
||
| ILogger logger = new LoggerConfiguration() | ||
| .MinimumLevel.Information() | ||
| .WriteTo.UiBus(logBus) | ||
| .CreateLogger(); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Stale comment: no Debug sink is configured.
The comment claims the logger is fanned out "plus Debug for local diagnostics," but the LoggerConfiguration only wires WriteTo.UiBus(logBus). Either drop the parenthetical or add the WriteTo.Debug() sink to match intent.
📝 Option A — fix the comment
- // UI log bus + a Serilog logger fanned out to it (plus Debug for local diagnostics).
+ // UI log bus + a Serilog logger fanned out to it.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // UI log bus + a Serilog logger fanned out to it (plus Debug for local diagnostics). | |
| var logBus = new UiLogBus(); | |
| services.AddSingleton(logBus); | |
| ILogger logger = new LoggerConfiguration() | |
| .MinimumLevel.Information() | |
| .WriteTo.UiBus(logBus) | |
| .CreateLogger(); | |
| // UI log bus + a Serilog logger fanned out to it. | |
| var logBus = new UiLogBus(); | |
| services.AddSingleton(logBus); | |
| ILogger logger = new LoggerConfiguration() | |
| .MinimumLevel.Information() | |
| .WriteTo.UiBus(logBus) | |
| .CreateLogger(); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Resgrid.Audio.Relay/App.xaml.cs` around lines 82 - 89, The logging setup in
App.xaml.cs is inconsistent with its comment because the LoggerConfiguration in
the logger initialization only uses WriteTo.UiBus(logBus) and does not include a
Debug sink. Update the implementation to match the intended behavior by either
adding the missing WriteTo.Debug() sink in the LoggerConfiguration chain or
removing the “plus Debug for local diagnostics” wording from the comment so it
accurately reflects the actual sinks configured.
| <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="10.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0" /> | ||
| <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.0" /> | ||
| <PackageReference Include="NAudio" Version="1.10.0" /> |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find all NAudio references (PackageReference and HintPath/Reference) across the solution.
rg -nP --type-add 'proj:*.csproj' -t proj 'NAudio' -g '!**/bin/**' -g '!**/obj/**'
# Surface any checked-in NAudio binaries/package folders.
fd -i 'naudio' -t f -e dll
fd -i 'naudio' -t dRepository: Resgrid/Relay
Length of output: 211
🏁 Script executed:
#!/bin/bash
# Search for NAudio references in csproj files
echo "=== searching csproj for NAudio ==="
find . -name "*.csproj" -type f | xargs grep -i "NAudio" 2>/dev/null
# Search for any existing NAudio package folders (old style)
echo "=== searching for packages/NAudio* folders ==="
ls -d packages/NAudio* 2>/dev/null || echo "No packages/NAudio* folder found at root"
# Check Resgrid.Audio.Relay.csproj specifically
echo "=== Resgrid.Audio.Relay.csproj content ==="
cat Resgrid.Audio.Relay/Resgrid.Audio.Relay.csprojRepository: Resgrid/Relay
Length of output: 2873
🏁 Script executed:
#!/bin/bash
# Search for NAudio references in csproj files
echo "=== searching csproj for NAudio ==="
find . -name "*.csproj" -type f | xargs grep -i "NAudio" 2>/dev/null
# Search for any existing NAudio package folders (old style)
echo "=== searching for packages/NAudio* folders ==="
ls -d packages/NAudio* 2>/dev/null || echo "No packages/NAudio* folder found at root"
# Check Resgrid.Audio.Relay.csproj specifically
echo "=== Resgrid.Audio.Relay.csproj content ==="
cat Resgrid.Audio.Relay/Resgrid.Audio.Relay.csprojRepository: Resgrid/Relay
Length of output: 2873
🏁 Script executed:
#!/bin/bash
# Verify the existence of the References folder and check its contents for NAudio binaries
# The guideline mentions: "Windows audio path depends on checked-in binary references from References\ and packages\NAudio.1.8.4\"
# We need to determine if the old 1.8.4 binaries still exist or if the project has fully migrated to the 1.10.0 PackageReference
echo "=== Check if References folder exists ==="
ls -la References/ 2>/dev/null || echo "References folder missing"
echo "=== List specific NAudio related items in References ==="
find References/ -name "*naudio*" -o -name "*NAudio*" 2>/dev/null || echo "No NAudio files found in References"
echo "=== Check Resgrid.Audio.Core references ==="
cat Resgrid.Audio.Core/Resgrid.Audio.Core.csprojRepository: Resgrid/Relay
Length of output: 1869
NAudio version mismatch with checked-in DtmfDetection binaries
The Resgrid.Audio.Relay.csproj (and dependencies) use NAudio 1.10.0 via PackageReference. However, Resgrid.Audio.Core references DtmfDetection.NAudio.dll from ..\References\, which was likely compiled against the older NAudio 1.8.4 indicated by the project guidelines.
Running NAudio 1.10.0 against a binary built for 1.8.4 may introduce API incompatibilities or runtime binding failures for DTMF detection. Verify that DtmfDetection.NAudio.dll is compatible with NAudio 1.10.0 or update the check-in binary to align with the current package version.
Current Configuration
Resgrid.Audio.Relay/Resgrid.Audio.Relay.csproj:
<PackageReference Include="NAudio" Version="1.10.0" />Resgrid.Audio.Core/Resgrid.Audio.Core.csproj:
<PackageReference Include="NAudio" Version="1.10.0" />
<Reference Include="DtmfDetection.NAudio">
<HintPath>..\References\DtmfDetection.NAudio.dll</HintPath>
</Reference>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Resgrid.Audio.Relay/Resgrid.Audio.Relay.csproj` at line 24, The NAudio
dependency version in Resgrid.Audio.Relay/Resgrid.Audio.Core is out of sync with
the checked-in DtmfDetection.NAudio binary. Verify DtmfDetection.NAudio.dll is
compatible with NAudio 1.10.0; if not, rebuild or replace the binary so it
matches the current NAudio package version. Update the references in
Resgrid.Audio.Core and any related project settings so the DtmfDetection path
and NAudio PackageReference stay aligned.
Source: Coding guidelines
|
|
||
| namespace Resgrid.Audio.Relay.Views | ||
| { | ||
| /// <summary>Placeholder About screen — filled in by the next UI pass.</summary> |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Stale doc comment. The summary calls this a "Placeholder About screen — filled in by the next UI pass," but the view is fully implemented (version, startup toggle, links). Update or remove the comment to avoid confusion.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Resgrid.Audio.Relay/Views/AboutView.xaml.cs` at line 6, The summary on
AboutView is stale and still describes the view as a placeholder even though the
page is implemented. Update or remove the XML doc comment on AboutView in
AboutView.xaml.cs so it accurately reflects the current behavior and features
exposed by the view, keeping the description aligned with the actual UI instead
of the old placeholder wording.
This comment has been minimized.
This comment has been minimized.
Kody Review CompleteGreat news! 🎉 Keep up the excellent work! 🚀 Kody Guide: Usage and ConfigurationInteracting with Kody
Current Kody ConfigurationReview OptionsThe following review options are enabled or disabled:
|
Summary
This PR introduces a complete WPF desktop GUI application for Resgrid Relay, replacing the console-only experience with a modern Windows application, and includes several engine reliability and correctness fixes.
Desktop GUI Application (Resgrid.Audio.Relay)
Engine Improvements (Resgrid.Relay.Engine)
Connectedonly after actual verification rather than optimistically at startup; Redis and TTS useUnknown(unprobed) instead of a stuckConnectingstateRESGRID__RELAY__env vars) with atomic writes and env-override detectionsmtpwhen mode is null or whitespaceBuild Configuration
Directory.Build.propsdefining theNET10_0_WINDOWSpreprocessor symbol for thenet10.0-windowsTFM, ensuring Windows-only code (radio/audio modes, device enumeration, WPF) compiles into the Windows build while staying excluded from cross-platform/Linux buildsSummary by CodeRabbit
New Features
Bug Fixes
Refactor