Add canvas.a2ui.pushJSONL as a Mac-compatible alias for the existing A2UI JSONL push handler.
Add device.info and device.status using the shared OpenClawKit payload shape, with Windows metadata/status sources plus tests and docs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduce a stable handler seam behind system.run to allow incremental
exec approval work without touching the current legacy path.
When no handler is injected (default), system.run runs byte-for-byte
identical to today. The new seam is inert until explicitly activated.
Adds minimum observability at the routing boundary: correlation ID,
selected path, decision, and reason code.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit a018dc054cbb85581baa37f92719bfcecee6d76f)
Keep the newer System.Drawing.Common 10.0.7 override from PR #219 after merging QR setup work and package audit changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep transitive NuGet vulnerability auditing enabled and add a direct System.Drawing.Common 10.0.7 reference so Microsoft.Toolkit.Uwp.Notifications no longer resolves vulnerable 4.7.0.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve setup bootstrap tokens separately from gateway tokens, support QR image and clipboard setup imports, and improve pairing notification copy flow.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add src/Directory.Build.props to align source projects on the recommended analyzer baseline and transitive NuGet vulnerability auditing.
Also allow .NET SDK feature-band roll-forward so the repo can build with installed 10.0.2xx SDKs while retaining the 10.0.100 baseline.
Supersedes #211
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds Windows node camera.clip, location.get, canvas local file serving/reload support, gateway command parity docs, and aligns screen capture with gateway-canonical screen.snapshot. Also makes camera.clip choose a supported Windows MediaCapture record stream and skips startup update prompts in debug builds for local node debugging.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Canvas windows now properly handle gateway-served content:
- Trust gateway origin: URLs from the connected gateway bypass the
private-network security filter (the node authenticated with this
gateway, so its content is trusted)
- URL rewriting: relative paths (/__openclaw__/...) are resolved to
the node's effective gateway origin (localhost when SSH-tunneled,
direct IP when on LAN)
- Bearer auth: WebView2 injects Authorization header for all gateway
requests via WebResourceRequested filter
- Window icon: Canvas window now shows the OpenClaw icon
Fixes canvas.present failing with 'URL blocked for security' and
'Navigation failed: Unknown' (401 unauthorized).
Part 1 (fixes#198): Move reconnect attempt counter reset from TCP
connect to application-level hello-ok handshake. Auth failures now
properly progress through backoff (1s→2s→4s→8s→15s→30s→60s) instead
of resetting to 1s on every attempt.
Part 2 (closes#199): Detect terminal auth errors (token mismatch,
origin not allowed, rate limited, signature exhausted) and stop
retrying entirely. Fire AuthenticationFailed event so the UI shows
a setup nudge in the tray menu.
Security: exhausted device signature modes (all 4 rejected) are now
treated as terminal — no infinite cycling. Error messages stay local
(log file + tray menu only, never sent externally).
Pairing success already sends a toast notification (Toast_NodePaired)
in all 5 locales.
* improve: FrozenDictionary command dispatch map in WindowsNodeClient
Replace O(n) linear capability scans with O(1) FrozenDictionary lookup.
- Add _commandMap field (FrozenDictionary<string, INodeCapability>)
- Add BuildCommandMap() to (re)build the map after each RegisterCapability call
- Replace both FirstOrDefault dispatch calls with _commandMap.GetValueOrDefault
- First-registered capability wins on command collision (preserves original semantics)
- Add 3 tests: routing, unknown command, first-registered-wins collision
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* improve: FrozenDictionary command dispatch map in WindowsNodeClient
Replace two O(n) FirstOrDefault(c => c.CanHandle(command)) scans
with O(1) FrozenDictionary lookup. TryAdd preserves first-registered-
wins semantics. Map rebuilt on each RegisterCapability() call
(startup only, before ConnectAsync).
Add event-path dispatch test to cover HandleNodeInvokeEventAsync
in addition to the request-path tests.
Based on Repo Assist PR #197, with additional test coverage.
Closes#197
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use range slice argv[1..] instead of argv.Skip(1).ToArray() (LINQ-free)
- Add SystemRun_SeparateArgsProperty_PolicyEvaluatesFullCommandLine: regression
guard ensuring policy evaluates the full 'rm -rf /' when args come from the
separate JSON 'args' property rather than the command argv array
- Add SystemRun_ShellFilter_PolicySkipsRuleForWrongShell: verifies that shell-
filtered rules (Shells=["pwsh"]) are not applied when a different shell (cmd)
is requested
588 Shared + 20 skipped; Tray unchanged.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace all Substring(0, n) calls in OpenClaw.Shared with the equivalent
C# 8+ range syntax (str[..n]) for readability and consistency with the
rest of the codebase.
Also remove the private TruncateLabel helper from OpenClawGatewayClient —
its logic was identical to the public MenuDisplayHelper.TruncateText.
The three call sites now delegate to MenuDisplayHelper.TruncateText(..., 60)
directly, and the reflection-based test helper is updated to match.
586 Shared + 122 Tray tests pass.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
_blockedNames is initialised once at startup and never mutated.
FrozenSet gives lower constant-factor O(1) Contains() compared to
HashSet, and matches the pattern already used throughout the codebase
(ChannelHealth.s_healthyStatuses / s_intermediateStatuses in Models.cs,
NotificationCategorizer.ChannelMap / IntentMap, etc.).
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The ListenForMessagesAsync method previously allocated a new byte[] of
16-64 KB per connection, which can land on the Large Object Heap and
increase GC pressure on long-lived connections. SendRawAsync already
uses ArrayPool<byte>.Shared, so this change makes the receive path
consistent.
Key changes:
- Replace new byte[ReceiveBufferSize] with ArrayPool<byte>.Shared.Rent
- Slice ArraySegment to ReceiveBufferSize to prevent ArrayPool oversize
from exposing extra bytes to ReceiveAsync
- Return buffer in a finally block covering all exit paths
No behaviour change; test suite unaffected (630 passed, 20 skipped).
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace string.Join(", ", tokens.Skip(i + 1)) with the indexed
string.Join(string, string[], int, int) overload in the three shell-
payload reconstruction sites (cmd /c, bash -c, powershell -Command).
Changes:
- Tokenize() now returns string[] instead of List<string>; callers
already received it as an opaque list so the type narrowing is safe.
- ParsePowerShellPayload signature updated to string[] to match.
- Three string.Join(" ", tokens.Skip(i + 1)) calls replaced with
string.Join(" ", tokens, i + 1, tokens.Length - i - 1) — uses the
well-known BCL overload that slices directly into the array with no
iterator allocation.
- Removes the now-unused 'using System.Linq;' import.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Lock in the zero-warning baseline achieved by PR #177. Any future
compiler or analyser warning in the test suite now becomes a build
error, preventing warning accumulation over time.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Each dotnet build / dotnet publish step that followed an explicit
dotnet restore was redundantly re-checking NuGet dependencies.
Adding --no-restore eliminates that I/O on every CI run.
Five steps updated: Build Shared Library, Build Tests (x2),
Publish WinUI Tray App, Build Command Palette Extension.
The WinUI test build (-r win-x64) is excluded: the generic
dotnet restore in the test job runs without -r win-x64, so
project.assets.json lacks that RID target and --no-restore
would fail with NETSDK1047.
Closes#195.
Co-authored-by: AlexAlves87 <alexalves87@github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add AutomationProperties.AutomationId to all interactive controls
- Add AutomationProperties.Name to 4 icon-only WebChat toolbar buttons
- Localize all SetupWizard strings via LocalizationHelper + .resw
- Replace hardcoded colors with ThemeResource brushes
- Replace raw FontSize with typography styles where appropriate
Prepares codebase for automated UI testing (winapp ui) and
proper Dark/Light/HighContrast theme support.
Add SetupWizardWindow with 3-step onboarding flow:
- Step 1: Paste setup code (auto-decodes URL+token) or manual entry
with connection test that understands pairing-required as success
- Step 2: Optional node mode with device ID and approve instructions
- Step 3: Done - saves settings and reconnects
Integration:
- Replace WelcomeDialog with wizard on first run (empty token)
- Add Setup Guide menu item to tray menu
- Add openclaw://setup deep link
- Guard node service against empty token (no crash)
- Contextual error messages for token mismatch, origin rejection,
rate limiting, and pairing required
Addresses #199
Tighten weak assertions identified during the three-model test-suite audit and enable the Shared integration test lane in CI.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace LINQ Select/Any with direct loops in three hot-path sites:
- ShellQuoting.FormatExecCommand: argv.Select(FormatSingleArg) →
preallocated string[] + for loop; avoids enumerator state-machine alloc
- LocalCommandRunner.BuildProcessArgs: request.Args.Select(...) →
preallocated string[] + for loop; same fix; drop unused System.Linq import
- ExecApprovalPolicy.Evaluate: rule.Shells.Any(...) → foreach with early
break; avoids closure + enumerator alloc on every command approval check
All three sites are in the system.run execution path and can be called
repeatedly. The for-loop variants are allocation-free for the iteration
itself and improve throughput under load.
586 Shared + 122 Tray tests pass.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Math.Round with C# default banker's rounding (MidpointRounding.ToEven) can
produce counterintuitive results at display-threshold boundaries:
- 59.5 minutes -> Math.Round(59.5) = 60 -> displayed as '60m ago'
instead of '59m ago' (or the correct transition to '1h ago')
- 47.5 hours -> Math.Round(47.5) = 48 -> displayed as '48h ago'
instead of '47h ago' (near the 48h/days boundary)
Using integer truncation ((int)delta.TotalX) matches the idiomatic
convention for age display: show the floor of the elapsed time, which
is consistent, predictable, and never exceeds the guard condition.
Adds three regression tests covering:
- 59.5-minute boundary (was '60m ago', now '59m ago')
- 47.5-hour boundary (was '48h ago', now '47h ago')
- Exactly 60 seconds (correctly '1m ago')
Test status: Shared.Tests 589 passed, 20 skipped; Tray.Tests 122 passed.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace per-character foreach+switch with System.Buffers.SearchValues<char>,
which uses SSE2/AVX2 vectorized IndexOfAny to detect shell metacharacters
in a single SIMD pass instead of a character-by-character loop.
- Add static SearchValues<char> s_shellMetachars (same 25-char set as former
- Replace NeedsQuoting foreach body with arg.AsSpan().IndexOfAny(s_shellMetachars) >= 0
- Remove private IsShellMetachar helper (no longer needed)
- Add using System.Buffers (SearchValues<T> namespace)
SearchValues<char> is available since .NET 8; this project targets net10.0.
All existing ShellQuotingTests pass unchanged.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
BuildProviderSummary is called on every gateway usage-status update.
The previous implementation allocated a List<string> (up to 3 entries)
and called string.Join, producing a heap-allocated list wrapper plus
join enumeration in addition to the final string.
With at most 2 provider slots + an optional overflow suffix, the
combinations fit into two nullable string variables and a switch
expression, producing only the final string allocation.
Also adds 9 unit tests covering all branch paths:
empty providers, single-provider with usage/error/no-windows,
two providers, three providers (overflow), missing display name,
all-empty providers, and overflow with one valid provider.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>