The Azure Trusted Signing dlib (x64) fails with exit code 3 when
running under emulation on the ARM64 runner (windows-11-arm).
Fix: Skip signing in the build/build-msix jobs for ARM64 targets.
Instead, sign ARM64 executables and MSIX packages in the release job,
which runs on windows-latest (x64) where the signing dlib works.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- GetSessionList_SortsMainSessionFirst now populates 3 sessions via
ParseSessions and verifies the main session is sorted first, instead
of only asserting an empty list.
- Added ParseSessionsPayload helper to expose the private parser.
- TaskbarAtBottom_TypicalScenario assertion changed from the tautological
'y + MenuHeight <= 1040 || y >= 0' to the strict 'y + MenuHeight <= 1040'.
571/571 tests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The 93-test Tray test suite (added in PR #45) was never wired into CI. Adds build + run steps for OpenClaw.Tray.Tests so all 571 tests validate on every push/PR.
Closes#58
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes two bugs that together caused issue #55:
1. Remove the healthList.Count > 0 guard so ChannelHealthUpdated fires even when all channels are removed.
2. Dispatch StatusDetailWindow.UpdateStatus when the window is already open.
3 new unit tests added. 478/478 shared tests pass.
Closes#55
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The TestLogger was silently swallowing all gateway client errors,
so connection failures showed a generic 'Connection failed' message.
Now captures the last error/warning and displays the actual gateway
message (e.g. 'origin not allowed') in the status label.
Also keeps verbose logging to Debug.WriteLine for dbgview-mcp
diagnostics.
Add structured logging to under-instrumented windows and services:
- StatusDetailWindow, SettingsWindow, ActivityStreamWindow,
NotificationHistoryWindow, QuickSendDialog, WelcomeDialog,
UpdateDialog, ActivityStreamService
- Replace raw Debug.WriteLine in CanvasWindow with Logger
- Use appropriate log levels (ERROR/WARN/INFO/DEBUG)
Closes#52
- Remove input.json.bak (stray backup file)
- Update README project structure (remove old OpenClaw.Tray, add
WinUI and test projects)
- Fix installer URLs to point at openclaw/openclaw-windows-node
instead of old shanselman/moltbot-windows-hub
WinUI tray has full feature parity plus Node Mode, Activity Stream,
session management, cost tracking, localization, and modern XAML UI.
- Remove src/OpenClaw.Tray/ (28 files, ~4900 lines)
- Remove from solution file
- Remove WinForms build step from CI
Installer already only references WinUI. Settings.json format is
unchanged — no migration needed.
Closes#44
Add null check on actions.SendMessage before invoking in the agent
deep link path. Removes null-forgiving operator that would throw
NullReferenceException inside Task.Run if the handler wasn't wired.
Adds warning log for diagnosability.
Fixes#47
Based on PR #48 by @Alix-007, adapted for current codebase.
Add WinUI .resw resource files for proper multi-language support:
- Strings/en-us/Resources.resw with all extractable UI strings
- Strings/zh-cn/Resources.resw with Chinese Simplified translations
- x:Uid attributes on XAML elements for automatic resource lookup
- LocalizationHelper for C# runtime string localization
- Windows auto-selects language based on OS locale
Any language can now be added by contributing a new .resw file.
Addresses #40
Extract testable pure logic from WinUI tray app into shared helpers:
- MenuDisplayHelper: status icons, text truncation, provider formatting
- DeepLinkParser: URI parsing for openclaw:// deep links
- MenuPositioner: tray popup positioning calculations
Create tests/OpenClaw.Tray.Tests with comprehensive coverage for
all extracted helpers plus settings serialization round-trips.
Closes#43
Use Tag attribute on WinUI ComboBoxItems to decouple display text
from persisted settings values. Load and save by Tag instead of
Content in SettingsWindow.xaml.cs.
Add documentation comment in WinForms SettingsDialog.cs making
the persistence contract explicit.
Backward compatible — existing settings.json values already match
the Tag keys. Worst case for unknown values: falls back to Default.
Fixes#41
ExecApprovalPolicy.Evaluate: normalizedShell was allocated inside the
foreach loop for every rule that carries a shell filter. Moving the
computation before the loop avoids the repeated allocation on the hot
command-evaluation path.
NotificationCategorizer.MatchesRule: the static Regex.IsMatch overload
that accepts a matchTimeout bypasses .NET's internal regex cache, so a
new Regex object was compiled on every incoming notification for each
regex-pattern user rule. Replace with a ConcurrentDictionary<string,
Regex?> that caches compiled instances (constructed with the 100 ms
timeout so ReDoS protection is preserved). Subsequent notifications
reuse the same compiled automaton.
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Extract duplicated metacharacter quoting logic from LocalCommandRunner
and SystemCapability into a shared ShellQuoting static class, following
the established GatewayUrlHelper pattern.
- ShellQuoting.NeedsQuoting: single source of truth for metachar detection
- ShellQuoting.QuoteForShell: shell-aware quoting (cmd vs PowerShell)
- ShellQuoting.FormatExecCommand: display formatting for gateway
- IsShellMetachar: idiomatic switch expression instead of duplicated
multi-case switch blocks
- 43 new unit tests covering all metacharacters, escaping edge cases,
null handling, and both shell modes
Co-authored-by: danedane <1402819+danedane@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review findings from PRs #29 and #32:
- QuoteArgIfNeeded: check all shell metacharacters (& | ; < > etc.),
not just whitespace/quotes — prevents command injection
- cmd.exe: use doubled-quote escaping (%"%") instead of backslash
which cmd doesn't recognize
- FormatExecCommand: align metacharacter checks with QuoteArgIfNeeded
so system.run.prepare shows the same command that actually executes
- StringBuilder: add lock around stdout/stderr event handlers and
ToString() reads to prevent concurrent-access corruption
Co-authored-by: danedane <1402819+danedane@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The gateway's nodes 'run' action requires system.run.prepare to build
an execution plan before the actual run. Without it, the only path is
the 'invoke' action which has a hardcoded 30s gateway timeout — too
short for long-running tools like Copilot CLI.
system.run.prepare echoes back the argv, cwd, rawCommand, agentId,
and sessionKey without executing anything, enabling the gateway to
use its configurable timeout path for the actual execution.
When system.run receives a command as an argv array, BuildProcessArgs
joins the args with spaces before passing to the shell. Args containing
spaces (e.g. a -p prompt like 'List all files') would be split into
separate tokens by the shell, causing tools like GitHub Copilot CLI
to report 'too many arguments'.
Added QuoteArgIfNeeded() that wraps args containing spaces, quotes,
or tabs in double quotes with proper escaping.
* fix(winui): stabilize tray menu placement and global hotkey
Improve Win10 tray context window positioning and make the Ctrl+Alt+Shift+C Quick Send hotkey reliably register and foreground the dialog.
* Address Copilot review feedback on PR #31
Fix 1: QuickSendDialog Closed handler race condition (App.xaml.cs)
- Use ReferenceEquals to only null the field when the closing dialog
is the current one, preventing a late Closed event from clearing
a newly-created replacement dialog.
Fix 2: Check PostMessage/Wait results in Register() (GlobalHotkeyService.cs)
- Treat PostMessage failure or wait timeout as deterministic failures
with clear logging, preventing _registered from being out of sync.
Fix 3: EnsureMessageLoop recovery (GlobalHotkeyService.cs)
- Check IsAlive and _hwnd, reset state and recreate the thread if
the previous message loop died, so the service can recover.
Fix 4: Dispose cleanup (GlobalHotkeyService.cs)
- Join the thread before DestroyWindow so the loop can exit cleanly.
- Dispose ManualResetEventSlim instances to prevent resource leaks.
Co-authored-by: xx299x <xx299x@gmail.com>
---------
Co-authored-by: xx299x <xx299x@gmail.com>
The build-msix (win-arm64) job was failing with MSB3030 because
the x64 GitHub Actions runner doesn't have the ARM64 apphost.exe
for cross-compilation.
Switch both build and build-msix jobs to use the free
windows-11-arm runner for ARM64 matrix entries, building natively
instead of cross-compiling.
* Initial plan
* Fix StatusIcon colour in Status dialog for 'ready' and 'active' channel statuses
Co-authored-by: shanselman <2892+shanselman@users.noreply.github.com>
* Centralize channel healthy-status check into ChannelHealth.IsHealthyStatus
Extract a shared static method ChannelHealth.IsHealthyStatus() in
OpenClaw.Shared to replace duplicated inline status checks across
the codebase. This ensures 'active' and 'ready' are consistently
recognized as healthy in all locations:
- StatusDetailWindow.xaml.cs (was missing active/ready - the original bug)
- App.xaml.cs flyout menu (was missing active/ready)
- App.xaml.cs channel toggle (was missing active/ready)
- TrayApplication.cs channel toggle (was missing active/ready)
Add comprehensive test coverage for the new helper method.
* Add intermediate status tier to Status dialog (yellow for idle/pending/connecting)
Address review feedback from @DanAtkinson: the Status dialog was
treating everything non-healthy as red, but intermediate statuses
like stopped, idle, paused, configured, pending, connecting, and
reconnecting should show yellow — matching the tray popup behavior.
- Add ChannelHealth.IsIntermediateStatus() shared helper
- Update StatusDetailWindow to use 3-tier coloring (green/yellow/red)
- Add test coverage for IsIntermediateStatus
* Fix flyout missing intermediate statuses; add mutual-exclusion tests
The WinUI flyout channel icon switch still had hardcoded
connecting/reconnecting instead of using IsIntermediateStatus(),
causing stopped/idle/paused/etc to show red instead of yellow.
Add mutual-exclusion test ensuring no status is ever classified
as both healthy and intermediate.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: shanselman <2892+shanselman@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
- bump OpenClaw.Tray and OpenClaw.Tray.WinUI project versions from 0.4.3 to 0.4.4
- bump WinUI MSIX package identity version from 0.4.3.0 to 0.4.4.0
- validated with win-arm64 Release builds for WinUI and Tray plus full OpenClaw.Shared.Tests pass
- synchronize App session preview cache reads/writes/removal with a dedicated lock to avoid cross-thread Dictionary access races between gateway events and tray menu rendering
- reset unsupported-method capability flags on successful gateway reconnect so usage.status, usage.cost, sessions.preview, and node.list can recover after transient or older-gateway errors
- add focused OpenClawGatewayClient regression test covering unsupported-flag reset behavior
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- bump OpenClaw.Tray and OpenClaw.Tray.WinUI project Version from 0.4.2 to 0.4.3
- bump WinUI MSIX manifest identity version from 0.4.2.0 to 0.4.3.0
- validated with win-arm64 Release builds for WinUI and Tray plus full OpenClaw.Shared.Tests pass
- add shared models and gateway client handling for session, usage, and node.list telemetry
- add ActivityStreamService plus ActivityStreamWindow flyout with filtering, clear, and dashboard jump actions
- wire WinUI tray actions/status surfaces for activity, node/session/usage updates, and one-time discoverability tip
- document exec-policy troubleshooting in README, including Windows policy path and powershell.exe argv[0] matching
- expand shared tests for model parsing and gateway client behavior
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Set OpenClaw.Tray and OpenClaw.Tray.WinUI project Version to 0.4.1\n- Set Package.appxmanifest identity version to 0.4.1.0\n- Keeps local/debug version metadata aligned so updater comparisons are less confusing
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add shared GatewayUrlHelper for ws/wss/http/https validation and normalization\n- Use helper in OpenClawGatewayClient and WindowsNodeClient\n- Reuse helper in WinForms/WinUI settings validation and NodeService A2UI URL derivation\n- Add gateway URL normalization tests for helper, gateway client, and node client
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rewrite UpdateDialog as proper WindowEx (fixes black square and XamlRoot crash)
- Size and center DownloadProgressDialog
- Add Debug level to IOpenClawLogger interface and all implementations
- Downgrade raw JSON, response payloads, channel health, and debug spew from Info to Debug
- Debug messages still visible in dbgview.exe via System.Diagnostics.Debug
- Delete 10 stale remote branches
- Update Package.appxmanifest Publisher to match Azure Trusted Signing cert subject
- Make build-msix continue-on-error so release isn't blocked by MSIX failures
- Add fail-fast: false to build-msix matrix
- Make MSIX artifact downloads in release job continue-on-error
Replace keyword-only classification with a layered pipeline:
structured metadata (intent/channel) > user rules > keyword fallback.
- Add Channel, Agent, Intent, Tags fields to OpenClawNotification
- Extract NotificationCategorizer class with layered pipeline
- Add NotifyChatResponses toggle to suppress chat toasts
- Add UserNotificationRule model for custom regex/keyword rules
- Map error notifications to urgent setting
- Add 30+ unit tests for categorizer pipeline
- Document categorization system in docs/
Per the official OpenClaw spec (nodes-tool.ts), the 'command' param
for system.run is an argv array (e.g. ["echo","Hello"]), not a string.
Our handler was rejecting array format, causing the first invoke
attempts from the agent to fail with 'Missing command parameter'.
Changes:
- Accept command as array (primary, per spec) or string (fallback)
- Support 'timeoutMs' param name (spec) alongside legacy 'timeout'
- Preserve backward compat for string command + separate args array
- Add 6 new tests for array/string/single-element/error/timeout cases
All 180 tests pass.
Add MSIX packaging support alongside existing Inno Setup/ZIP distribution.
The build now supports both packaged (MSIX) and unpackaged (EXE) modes
via the PackageMsix MSBuild property.
MSIX packaging enables:
- Native Windows camera/microphone consent prompts
- Package identity for OS integration
- Protocol activation for openclaw:// deep links via manifest
Changes:
- csproj: Conditional WindowsPackageType (None vs MSIX) toggled by
-p:PackageMsix=true. Self-contained in both modes. ApplicationVersion
synced from Version property for MSIX.
- Package.appxmanifest: Declares webcam, microphone, internetClient
capabilities. Protocol handler for openclaw://. Visual assets.
- PackageHelper.cs: Runtime detection of packaged vs unpackaged mode
via Windows.ApplicationModel.Package.Current
- App.xaml.cs: Protocol activation handling via AppInstance lifecycle API
for MSIX deep links. Works alongside existing command-line deep links.
- DeepLinkHandler.cs: Skip registry URI registration when packaged
(manifest handles it)
- ci.yml: New build-msix job (x64 + ARM64) parallel to existing build.
MSIX signing via Azure Trusted Signing. MSIX artifacts in releases.
Null-check on MSIX find step.
- Visual assets: Generated PNG logos for MSIX package tiles
- README: Added MSIX build instructions
Build modes:
dotnet build -r win-arm64 # Unpackaged (default)
dotnet build -r win-arm64 -p:PackageMsix=true # MSIX package
Note: MSIX Publisher in Package.appxmanifest must match the Azure
Trusted Signing certificate subject exactly. Currently set to
'CN=Scott Hanselman' - update if cert subject differs.