Skip to content

fix(exec): restore V2 approval parity - #6

Closed
bkudiess wants to merge 180 commits into
mainfrom
bkudiess-investigate-exec-policy-regression
Closed

fix(exec): restore V2 approval parity#6
bkudiess wants to merge 180 commits into
mainfrom
bkudiess-investigate-exec-policy-regression

Conversation

@bkudiess

@bkudiess bkudiess commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • replace the stale V1-shaped Permissions editor with the file-backed V2 policy model used by runtime, MCP, and the Gateway
  • expose Defaults, All agents (*), main, and existing agent scopes with security, ask, askFallback, autoAllowSkills, and executable-path allowlists
  • show explicit guidance for rejected V1 command patterns, preserve input on failure, reload safely after CAS conflicts, and surface durable read/write errors
  • add upstream-compatible generated approval identity: source: "allow-always" plus a length-delimited SHA-256 argPattern of the exact argv tail
  • require path and argument matches for generated grants, ignore legacy generated path-only grants, preserve intentionally broad manual path rules, and protect complete authority tuples during currency checks and remote CAS updates

Architecture ownership

  • Old owner: PermissionsPage.xaml.cs directly read, mutated, and persisted exec approval state for main only.
  • New owner: PermissionsPageViewModel plus IExecApprovalsPolicyStore own snapshot projection, exact scope selection, validation, CAS mutation/retry, rollback, and tuple preservation.
  • Preserved invariant: the UI, system.run, system.execApprovals.get/set, local MCP, and Gateway relay share one authoritative ExecApprovalsStore; generated authority is identified by (pattern, argPattern, source).

Validation

  • ./build.ps1
  • dotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj --no-restore ✅ 3,397 passed, 32 skipped
  • dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore ✅ 2,055 passed
  • dotnet test ./tests/OpenClaw.WinNode.Cli.Tests/OpenClaw.WinNode.Cli.Tests.csproj --no-restore ✅ 126 passed
  • ./scripts/validate-mxc-e2e.ps1 -NoBuild ✅ 2/2 real Gateway → Windows node → MXC proofs passed
  • focused real-process WinUI proof ✅ 1 passed; Axe.Windows found 0 violations

Real behavior proof

  • entering legacy hostname is rejected with visible executable-path guidance and associated UIA HelpText
  • **/where.exe saves under All agents, survives navigation/reload, and exposes a named removal control
  • generated entries display Arguments restricted to the approved command. without exposing plaintext arguments
  • system.execApprovals.get returns source and argPattern; MCP discovery includes get/set/run
  • generated whoami.exe zero-argument grant: decision=allow, promptAttempted=false
  • changed whoami.exe /all: AllowlistMiss, promptAttempted=false
  • attempted remote argPattern rewrite is rejected and the stored hash remains unchanged
  • local UI screenshot captured from current head as exec-approvals-v2.png (150,526 bytes); not attached to this initial draft

Review

  • security-sensitive read-only review found case-sensitive scope, accessible validation, tuple removal, and legacy manual-conversion issues; all were fixed and the final recheck was clean
  • the structured autoreview helper failed closed because full localization-file snapshots exceeded its 180 KB bundle limit; no limit bypass was used

Deferred security design

  • explicit per-command/executable deny rules remain absent from both current file-backed implementations and need a separate design
  • canonical cwd filesystem identity and mutable script-content launch revalidation remain follow-up hardening
  • hand-authored path-only rules remain intentionally broad; generated Always Allow rules are argument-bound

bkudiess and others added 30 commits June 24, 2026 12:41
Adds app-managed WSL gateway recovery actions to the setup wizard, moves shared WSL gateway helpers into OpenClaw.Connection, and documents the recovery behavior.
Fixes the Settings hotkey to open the Settings page and refreshes the MXC helper restore so stale helper binaries are not reused while keeping npm restore incremental.
Ports the MXC probe/SDK 0.7.0 work and inbound pairing approval dialog from the mistaken master branch target onto main.

Maintainer repair included:
- Preserving non-actionable handling for ambiguous legacy pairing fallback IDs in the new approval queue.
- Adding regression coverage for device and node fallback ambiguity.
- Version-stamping MXC SDK restore so stale node_modules cannot satisfy the 0.7.0 port.

Validation:
- Local .\build.ps1 passed.
- Local Shared tests passed: 2411 passed / 29 skipped.
- Local Tray tests passed: 1127 passed.
- Local Connection tests passed: 373 passed.
- GitHub CI passed on repaired head 7be0688: test, E2E setup-connect, E2E revocation-recovery, E2E network-recovery, build win-x64, build win-arm64, repo-hygiene.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Routes local system.run approval prompts into native chat when an interactive chat surface is available, while preserving the native approval dialog fallback.

Maintainer updates:
- Rebased onto current main after the MXC/pairing port landed.
- Kept the deleted Chat Explorations fake provider removed during rebase.
- Removed a duplicate ChatWindow.Show() call introduced during the branch hardening pass.

Validation:
- Local .\build.ps1 passed.
- Local Shared tests passed: 2417 passed / 29 skipped.
- Local Tray tests passed: 1154 passed.
- Independent code review found only the duplicate Show() issue, now fixed.
- Independent security review found no concrete security vulnerabilities.
- GitHub CI passed on repaired head ae301c0: repo-hygiene, test, E2E setup-connect, E2E revocation-recovery, E2E network-recovery, build win-x64, build win-arm64, Socket Security.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Merged after daily triage: focused scope, green CI, and low-risk validation evidence.
Merged after daily triage: focused scope, green CI, and low-risk validation evidence.
Merged after daily triage: focused scope, green CI, and low-risk validation evidence.
Merged after rerunning the failed setup-connect shard successfully; follow-on win-x64 and win-arm64 builds also passed.
Adds a static gateway protocol snapshot guard covering sessions, files, commands, and compaction, with maintainer repair so no-parameter used request methods are also checked for payload drift.
Improves Cron History so users can inspect full sanitized run responses, preserves expanded/running state while refreshing, adds response-aware cron.run feedback, and includes compatibility coverage for legacy cron.run payload fallback.
Route selected background issues into the in-app Notifications page, including connection, sandbox, channel, pairing, and cron failures. Partially addresses openclaw#820; it does not close the broader notification-routing issue.
* Make A2UI dataModelUpdate.valueArray first-class

The v0.8 `dataModelUpdate.valueArray` typed value was silently dropped by the
WinUI parser: `DataModelEntry` had no `ValueArray` field and `ToJsonNode()`
returned null for it. Only `valueString/Number/Boolean/valueMap` were handled.
This broke seeding an array into a surface's data model (e.g. a multi-select
`MultipleChoice` bound to a path), even though `valueArray` is part of the v0.8
protocol (docs/a2ui/protocol.md §2.2 and data-and-actions.md).

Changes:
- Parser (A2UIProtocol.cs): add `DataModelEntry.ValueArray`; `ToJsonNode()`
  emits a `JsonArray`; new `ParseValueArray`/`ParseArrayElement` handle
  value-typed object elements, bare primitives (`["a",1,true]`), nested
  maps/arrays, and preserve JSON null as a stable index slot.
- DoS guard (DataModelStore.cs): the 32-deep depth bound now recurses
  `valueArray` as well as `valueMap`.
- Security (SecretRedactor.cs): the array branch now redacts registered/
  denylisted element paths instead of only recursing, so a secret seeded into
  an array (e.g. an obscured field bound to /codes/0) no longer leaks via
  canvas.a2ui.dump.
- Docs (SKILL.md): correct the stale "arrays are not first-class" note.

Tests: parser coverage for valueArray (strings, mixed scalars, maps, nested
arrays, bare primitives, empty, null slots) plus valueMap/scalar regressions;
secret-redaction regressions for secrets inside arrays; store-level base-path
landing and depth-guard rejection; and an end-to-end MultipleChoice surface
seeded via valueArray that asserts both the snapshot and the rendered
preselection.

Validation: build.ps1 (all projects), Shared.Tests, Tray.Tests, and A2UI
UITests all pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix valueArray redaction and notifications

Reject non-canonical array pointer indices for data-model array access, notify descendant subscribers when container values are replaced, and redact registered secret descendants when action contexts or snapshots include parent paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
* Fix canvas navigation URL handling

* Fix canvas navigate dispatcher timeout

Route canvas.navigate through the same dispatcher timeout guard used by canvas.eval and canvas.snapshot so stalled UI dispatch cannot hang MCP tool calls indefinitely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Scott Hanselman <scott@hanselman.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add TTS provider fallback and tts.status readiness command

When the requested/configured TTS provider isn't usable (no ElevenLabs key,
Piper voice not downloaded), gracefully fall back to Windows TTS instead of
throwing, and report the effective vs requested provider plus a fellBack flag.
A stale configured Windows voice now degrades to the system default voice so
the fallback always speaks.

Add a tts.status node command that reports per-provider readiness
(ready/needs-api-key/needs-voice/voice-not-downloaded/unavailable) plus the
configured/effective provider and willFallBack. PII-free. Wired across
DangerousCommands gating, MCP descriptions, skill.md, and the setup allowlist
export. Fix a stale pre-GA SHA-256 TODO docstring in PiperVoiceManager
(verification is already implemented and enforced by AssetHashPinningTests).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Preserve configured TTS fallback for chat playback

Leave chat playback provider unset so TextToSpeechService can distinguish configured/default playback from explicit provider requests and apply the new Windows fallback when the configured provider is unavailable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
Validate screen.snapshot image formats before invoking the capture backend, normalize jpg to jpeg, and derive the response data URI MIME type from the validated format instead of the backend echo.

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…w#824)

* Wizard protocol resilience: progress/non-interactive steps, auth prompts, restart hardening

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Harden wizard progress polling budget

Allow a single long-running gateway progress step to use the full bounded progress budget instead of failing after the previous shorter per-step cap. Share the progress constants between the setup runner and UI and cover the intended budget in tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
Measure the tray popup against its final client width and apply pixel-exact window sizing so wrapped content determines height deterministically.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Normalize the Sandbox page toggle off when MXC is definitively unavailable, reject turning it back on in the host-fallback mode, and preserve strict fallback blocking so users who opted into command denial remain protected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Squashed from PR openclaw#800 after maintainer review and local fixes.\n\nLocal validation:\n- .\\build.ps1\n- dotnet test .\\tests\\OpenClaw.Shared.Tests\\OpenClaw.Shared.Tests.csproj --no-restore\n- dotnet test .\\tests\\OpenClaw.Tray.Tests\\OpenClaw.Tray.Tests.csproj --no-restore\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* test: add Gateway MXC runtime E2E proof

* test: probe MXC E2E gate with discovered wxc-exec

* test: extend Gateway MXC E2E timeout budgets

* test: avoid blocked redirection in Gateway MXC deny proof

* test: prove MXC denied copy reaches destination

* test: document serialized MXC E2E collection gate

* test: raise MXC E2E sandbox timeout cap

* test: approve MXC denied-write copy proof step

* test: sync MXC approval proof diagnostics

* test: narrow MXC exec approval proof policy

* ci: extend setup-connect E2E timeout

Give only the setup-connect E2E shard extra time for the combined setup and MXC runtime proof fixtures while leaving the other E2E shards on the existing budget.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix: omit unsupported MXC denied paths

Windows wxc-exec rejects filesystem.deniedPaths before launching the sandboxed command. Keep denied paths as the local allow-list filter, but omit the unsupported backend field so AppContainer default-deny can run the command while still stripping parent/exact grants over sensitive paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Vitor Cepeda Lopes <7040636+TheAngryPit@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
)

* Improve remote gateway setup and connection error recovery

Add RemoteGatewayClassifier + GatewayErrorClassifier in OpenClaw.Shared and
wire ConnectionPage remote setup advice, scope/token-drift/TLS recovery, and
localized strings.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Clear stale SSH fields for setup-code flow

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
* Node mode UI: surface MCP-only/connecting states and repair gateway-node gating

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix MCP-only node status visibility

Surface the local MCP-only node card even when no gateway/operator session exists, and make the reconnect-backoff test wait for server-side accept publication.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Keep MCP-only mode from joining gateways

Gate the post-operator local NodeService auto-connect on EnableNodeMode so local MCP-only serving does not create gateway node pairing requests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Request node reconnect in shared-token setup E2E

The shared-token setup path can now remain MCP-only after operator approval, so the E2E needs to request node reconnect explicitly before waiting for a node credential.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
)

A connection/auth failure rendered two error bars: the global top-window
InfoBar plus an in-page "Connection Error" InfoBar on the Connection page.
The auth pipeline also published two global notifications for one failure,
which forced the banner action to degrade to "Show more".

Remove the in-page AuthErrorBar and consolidate to one top banner that:
- carries the gateway/node error states the in-page bar covered
- always routes the user to the Connection page via an "Open Connection"
  action (connection notifications are prioritized as the visible banner,
  preferring an actionable one over an action-less transient)
- renders as a single thin line: bold headline + " - detail", with the
  action as a right-aligned hyperlink (Windows-aligned InfoBar)

Other changes:
- Stop publishing the duplicate connection:authentication-failed banner;
  the snapshot-driven connection:issue notification is the single source.
- Re-home transient errors: WSL host-action failures use the inline card
  status (or a top notification when the card is hidden); connect/switch
  failures publish via ShowTransientConnectionError on the same banner id.
- Remove now-dead resw strings (ConnectionPage_AuthGuidance*,
  ConnectionPage_ConnectFailed) across all five locales.

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add tray live dashboard glance

Add a compact status summary to the tray flyout that surfaces gateway health, refresh freshness, session and usage metrics, and the current session preview before the existing action rows.

Wire a Diagnostics action into the tray menu and keep the summary computation in a testable, render-free builder shared by existing usage/session rows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Remove message previews from tray glance

Keep the tray dashboard focused on health, freshness, session metadata, and usage while avoiding conversation message text in the top-level flyout.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Avoid activity snippets in tray dashboard glance

Keep the top-level tray dashboard limited to stable metadata so command, query, path, or URL activity text stays out of the glance.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
Move notifications from the footer rail into a title-bar bell flyout and replace the compact connection status dots with a status pill plus detail flyout. Keep the status presentation aligned with the Connection page by deriving node state from shared presenter logic and the node-mode/capability settings.

Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Port PR openclaw#562 onto current main and harden diagnostics redaction so JSONL remains parseable while sensitive values, metadata keys, paths, emails, headers, and compound JSON values are sanitized before export.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
calebeden and others added 28 commits July 21, 2026 15:59
…law#1036)

* feat: add native lifecycle slash commands

Handle exact /new, /reset, and /compact commands through lifecycle RPCs, preserve structured compaction boundaries, and retain safe compatibility behavior for older gateways.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c41e789a-73e3-41ae-ac62-1ff5287599c0

* fix: harden lifecycle command edge cases

Preserve explicit session selection and failed composer sends, retain live entries during authoritative reloads, widen compaction metrics, and clarify lifecycle timeout recovery.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c41e789a-73e3-41ae-ac62-1ff5287599c0

* fix: order lifecycle commands with queued sends

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c41e789a-73e3-41ae-ac62-1ff5287599c0

* fix: guard authoritative history reload pending by connection generation

The _authoritativeHistoryReloadPending flag was consumed in
LoadHistoryCoreAsync's finally block without checking whether the
completing request belonged to the current connection generation.
A stale old-generation completion after disconnect/reconnect could
consume the flag and trigger an unintended authoritative reload
in the newer generation.

Fix:
- Only consume/schedule the pending authoritative reload when
  requestConnectionVersion == _historyConnectionVersion (same
  guard as _historyInFlight removal)
- Clear _authoritativeHistoryReloadPending in
  AdvanceHistoryGenerationLocked so generation advances invalidate
  stale pending flags
- Add deterministic regression test:
  StaleGenerationAuthoritativeReload_DoesNotReloadInNewGeneration

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d2982ca8-bb56-4728-85bd-29542ce9d554

* Record paired-review history race fix

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4f0e93ff-d320-454d-b00a-865dac727d0c

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
)

* feat: add native lifecycle slash commands

Handle exact /new, /reset, and /compact commands through lifecycle RPCs, preserve structured compaction boundaries, and retain safe compatibility behavior for older gateways.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c41e789a-73e3-41ae-ac62-1ff5287599c0

* improve(hub): move Settings nav item to footer under Diagnostics

Match the WinUI standard of pinning Settings to the very bottom of the
navigation pane. Moves the Settings NavigationViewItem out of MenuItems
into FooterMenuItems, placed after Diagnostics. Navigation still resolves
via both collections and the high-contrast icon swap already covers footer
items, so behavior is unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* improve(chat): make welcome suggestion buttons subtle

Drop the default button stroke and elevation depth from the three
zero-state prompt suggestions (Say hi, What can you do?, Give me a quick
tour of OpenClaw), keeping only a light, low-opacity fill at rest via
SubtleFillColorSecondaryBrush. Rounded corners, padding, and hover
feedback are unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Make chat composer theme-aware in dark mode

The composer read as light gray on a dark chat surface and its fade
gradient stayed white because FunctionalUI resolved theme brushes by
walking the app-level ThemeDictionaries, which do not surface WinUI's
XamlControlsResources framework brushes. Controls rendering dark fell
back to the light Application.Resources snapshot.

Fixes, using only built-in WinUI theme resources (no hardcoded colors,
no C# theme helper):

- App.xaml: re-declare the exact framework brush keys the chat uses in
  the Default/Light/HighContrast theme dictionaries, each aliasing its
  built-in color token via ThemeResource. Values are identical but now
  reachable by the per-theme walk, so they flip correctly.
- FunctionalUI: resolve foreground/background/border resource brushes
  against the control's ActualTheme and re-apply reactively on
  ActualThemeChanged/Loaded so brushes flip on a runtime light/dark
  switch.
- Composer: send/stop glyphs and fills, session-picker rows, and the
  welcome suggestion buttons resolve against ActualTheme instead of
  snapshotting the app theme; the fade gradient derives from the
  now-correct base-surface brush so it fades into the dock in dark.
- Timeline: timestamp/helper captions resolve TextFillColorSecondary
  for the timeline root's ActualTheme so they stay legible in dark.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: harden lifecycle command edge cases

Preserve explicit session selection and failed composer sends, retain live entries during authoritative reloads, widen compaction metrics, and clarify lifecycle timeout recovery.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c41e789a-73e3-41ae-ac62-1ff5287599c0

* improve(hub): restyle title bar and float notification banner

Merge the pane toggle into the lobster logo (hover reveals a DockLeft
panel icon), move the back button to a chevron directly left of a
centered search box, and give the title-bar icon buttons a subtle
hover/pressed affordance.

Make the right-side status/error pill transparent at rest (border kept
for its dropdown) and the notification bell a true borderless subtle
button. Convert the app notification banner to a native WinUI InfoBar
with Title/Message and a standard ActionButton, and float it over the
top-right of the content area (right ~2/5) so it never pushes the title
bar or nav content down. Long messages wrap and grow the banner taller.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: order lifecycle commands with queued sends

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c41e789a-73e3-41ae-ac62-1ff5287599c0

* fix(functionalui): resolve theme color via paired brush token

ResolveColor threw InvalidOperationException when a raw WinUI color token was absent, which happens in minimal hosts (including the UI test surfaces) that seed only the paired '<key>Brush'. The chat timeline resolves TextFillColorSecondary during render, so the throw aborted the whole mount and the timeline rendered no ItemsRepeater, failing the chat proof tests. Fall back to the paired brush's color before throwing; both forms resolve to the same value in production. Adds a regression test covering the brush-color fallback and the still-missing-token throw.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): eliminate ActualThemeChanged handler accumulation in .Set() lambdas

Replace 7 repeated event subscriptions inside .Set() render paths with:
- Theme.EnsureThemeCallback: ConditionalWeakTable-based single-subscription
  utility that stores and replaces the latest callback per control, invoking
  it immediately and on theme/load events (once, never accumulating).
- FunctionalUI modifier path (.BackgroundResource / .Background(Ref(...))):
  for constant resource keys on Borders and Buttons, reuse the existing
  TrackThemedBrushes mechanism which already guards first-time subscription.
- Control.Background support in ApplyModifiers + ReapplyThemedBrushes: the
  narrow renderer extension needed for Button backgrounds.

Also remove the dead RootGrid Row 1 (formerly the InfoBar, now floating
in Row 1 as an overlay).

Regression tests prove:
- 100 EnsureThemeCallback calls store exactly one callback (latest state)
- FunctionalUI renderer applies BackgroundResource to Controls correctly

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 103120e9-d856-456c-885c-1ffd529b8746

* fix(chat): render composer fade gradient dark in dark mode

The composer scrim derived its color by reading .Color off the framework
SolidBackgroundFillColorBaseBrush out of the visual tree, so its
{ThemeResource} re-resolved against the ambient light app theme and the
fade read white (#F3F3F3) on a dark page.

Add a dedicated ChatComposerFadeBrush to App.xaml ThemeDictionaries with
literal per-theme colors (dark #202020, light #F3F3F3, high-contrast
follows SystemColorWindowColor) and resolve it as a whole brush per
ElementTheme, so it flips correctly and stays aligned with the composer
dock fill. App-defined theme dictionaries are reachable by the
FunctionalUI theme walk; framework primitives are not.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: guard authoritative history reload pending by connection generation

The _authoritativeHistoryReloadPending flag was consumed in
LoadHistoryCoreAsync's finally block without checking whether the
completing request belonged to the current connection generation.
A stale old-generation completion after disconnect/reconnect could
consume the flag and trigger an unintended authoritative reload
in the newer generation.

Fix:
- Only consume/schedule the pending authoritative reload when
  requestConnectionVersion == _historyConnectionVersion (same
  guard as _historyInFlight removal)
- Clear _authoritativeHistoryReloadPending in
  AdvanceHistoryGenerationLocked so generation advances invalidate
  stale pending flags
- Add deterministic regression test:
  StaleGenerationAuthoritativeReload_DoesNotReloadInNewGeneration

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d2982ca8-bb56-4728-85bd-29542ce9d554

* Record paired-review history race fix

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 4f0e93ff-d320-454d-b00a-865dac727d0c

---------

Co-authored-by: Caleb Eden <58373773+calebeden@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
…claw#1048)

The Welcome step wrapped two accent-bordered cards in a RadioButtons group while also swapping the card border on selection, so each option showed two selection indicators (radio ellipse + highlighted card). Replace it with a single-select ListView whose built-in Fluent selection pill is the sole indicator, matching the ListView pattern already used by WizardPage. Vertically center the icon tiles so they align with the title/caption block.

Delete the now-redundant UpdateCardSelection border-swap logic and its call sites, and enforce an always-one-selected invariant in the SelectionChanged handler (a single-select ListView can otherwise be cleared to no selection). Add AutomationProperties.HelpText for the choice group and harden the WelcomePage contract test to lock in single-select, disabled inner scroll, the wired handler, and absence of the old card chrome.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ode (openclaw#1045)

* feat: add display sanitizer for exec approval command text

Command text shown in an approval prompt can carry invisible or
direction-changing code points (BiDi overrides, zero-width characters, fake
line breaks, non-ASCII spaces) that let an agent make the approved text look
like a different command. Add a rune-based sanitizer that escapes those code
points as \u{HEX} before any UI binding, leaving legitimate text untouched.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add exec approval prompt handler core

Add the UI-free core behind the approval prompt: a handler that sanitizes the
command, working directory, and resolved path, builds a display-ready view, and
resolves the outcome behind two injected delegates (dispatcher enqueue + show
dialog) so its full behavior is testable without WinUI. It is fail-closed:
never throws, never returns a plain allow, and denies on cancellation, enqueue
failure, window close, or any internal error.

Also flag mixed-script confusables (Latin intermixed with Cyrillic or Greek,
the homoglyph-spoofing signal from Unicode UTS openclaw#39) so the dialog can warn the
user. Confusables are not escaped — that would mangle legitimate non-ASCII
text — only reported.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add exec approval prompt dialog

Add the WindowEx approval window built in code like the existing pairing and
recording-consent dialogs (the tray has no reliable XamlRoot for ContentDialog).
It shows the sanitized command in a monospaced, selectable card plus optional
context rows, and offers Deny / Allow Once / Allow Always.

Security posture: the allow buttons are never default-focused and arm only once
a short delay has elapsed AND the whole command has been scrolled into view, so
a long command cannot be approved with its dangerous tail off-screen. Escape,
the close button, and Alt+F4 all resolve to Deny. A caution row appears when the
command trips the mixed-script confusable check. Strings added to all five
locales.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: wire the real approval dialog behind the prompt-handler seam

Replace the null prompt handler in the coordinator construction with a thin
WinUI adapter that supplies the real dispatcher hop and dialog window to the
shared handler core. The coordinator keeps the always-cannot-present evaluator,
so the dialog stays dormant until a real presentation gate lands: the new path
remains inert (opt-in flag off and presentation gated off). Update the log
message to reflect that the prompt dialog is wired.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: AlexAlves87 <alexalves87@github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…er a settings store

Moves Settings page read and persistence logic into a WinUI-free view model backed by a settings store, wires navigation activation, and adds behavioral coverage for the new ownership seams.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Project command titles into the shell AutoSuggestBox and use them as the fallback string representation so CLR type names do not leak into selected text or accessibility names.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…000.2526 (openclaw#1060)

---
updated-dependencies:
- dependency-name: Microsoft.Windows.SDK.BuildTools
  dependency-version: 10.0.28000.2526
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
updated-dependencies:
- dependency-name: Microsoft.ML.OnnxRuntime
  dependency-version: 1.28.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* Add MCP server lifecycle telemetry

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Link MCP requests to tool telemetry

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: harden MCP lifecycle telemetry

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f
* Keep Windows device metadata stable on reconnect

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* test: strengthen reconnect metadata coverage

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f
* Fix device identity load failures

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Harden identity failure recovery

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f
* feat: replace legacy exec approvals with V2

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: prevent remote exec policy weakening

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* docs: describe V2 as the active approval pipeline

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: close exec approval review bypasses

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: harden approval redaction boundaries

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
….3 (openclaw#1058)

Bumps [github/gh-aw-actions/setup-cli](https://github.com/github/gh-aw-actions) from 0.82.13 to 0.83.3.
- [Release notes](https://github.com/github/gh-aw-actions/releases)
- [Changelog](https://github.com/github/gh-aw-actions/blob/main/CHANGELOG.md)
- [Commits](github/gh-aw-actions@a5d8b7d...6f8e8ef)

---
updated-dependencies:
- dependency-name: github/gh-aw-actions/setup-cli
  dependency-version: 0.83.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…penclaw#1053)

* fix: recover managed local gateway connections

Add trusted endpoint provenance, role-aware credential recovery, explicit operator intent, and bounded managed-WSL repair so local gateway failures recover safely without leaking stronger credentials or overriding disconnects.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: verify WSL relay ownership during setup

Preserve WSL shell variables through stdin, isolate the Windows PowerShell module path for Authenticode verification, and account for relay family translation. Update the keepalive E2E contract to recognize an already-proven setup keepalive without spawning a duplicate.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: constrain managed gateway ownership migration

Adopt setup-managed ownership only when setup state proves the same loopback endpoint, preserve manual and SSH-backed records, deduplicate external provenance probes, and record the repair ownership boundary in the architecture ledger.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix: drop managed ownership when endpoint changes

Preserve setup-managed metadata only for component-equivalent endpoints, strip stale explicit and legacy ownership on repoint, and cover standard versus nonstandard loopback aliases plus case-sensitive path and query changes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* docs: define default-on local gateway recovery

Document the macOS-parity supervision contract, persist the default for fresh setup, verify existing settings inherit it, and preserve an explicitly disabled kill switch across setup reruns.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Scott Hanselman <scottha@microsoft.com>
Copilot-Session: f5f0e4a6-88fa-4782-9a60-5648648fda3e
* build: add Reactor dependency

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* feat(chat): migrate chat page to Reactor

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* feat(chat): add annotated scrollbar

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* improve(chat): match seeded composer design

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* improve(chat): refine message timeline interactions

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): position initial history at tail

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): rearm initial tail positioning

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): harden composer paste and tail positioning

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* ci: add ClawSweeper dispatch workflow

* Fix chat session picker visibility

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f

* feat(chat): restore slash command palette

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): honor display settings

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): suppress no_reply directives

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): settle returning-user welcome

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): bound queued message list

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): preserve dismissed slash palette

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* chore(chat): checkpoint stable items view

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): follow native items view state

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): follow items view viewport

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* fix(chat): scope Reactor diagnostics

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Co-authored-by: Scott Hanselman <scott@hanselman.com>
Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f
…#1070)

* fix(connection): recover registry-backed SSH tunnels

* fix(connection): harden SSH tunnel recovery

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f

---------

Co-authored-by: Scott Hanselman <scott@hanselman.com>
Copilot-Session: 7b9bc681-ce19-4a8b-b06c-94efb63a5f9f
…aw#1066)

* fix(tray): explain browser proxy when shared gateway token is missing

Setup-code pairing can connect without a SharedGatewayToken, which silently skipped browser capability declaration and left the UI stuck on Enabled, not active yet. Surface Needs gateway shared token, warn in Command Center, and log the concrete skip reason.

Refs: openclaw/openclaw#115989

* fix(tray): separate browser proxy no-client from missing-token UI

Only show Needs shared token / Command Center guidance when a node client is attached; disconnected gateways should not tell operators to paste a token.

* fix(tray): align browser.proxy missing-token UX across live session surfaces

Use manager NodeState for remediation, and share topology-aware remote/SSH
endpoint guidance across Connection pill tooltips, Command Center, and
app.connection diagnostics so token-only copy does not overpromise.
Migrate chat and Connection presentation to WinUI theme resources, preserve system-colored Hub navigation in High Contrast, and add runtime coverage for isolated tool and compaction styles.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use stable native anchoring for streamed chat growth and validate immutable queued tail requests against current identity, bounds, item count, and generation before native navigation.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* feat(sessions): consume flattened gateway classification

* test(sessions): fix flattened facts test syntax

* fix(sessions): preserve legacy display fallback

* fix(sessions): reject raw key display names

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: bakudies@microsoft.com <bakudies@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace the stale V1-shaped Permissions editor with the file-backed V2 policy model, explicit validation, scoped rules, and CAS-safe persistence. Add upstream-compatible argument-bound generated grants so changed argv no longer reuses Allow Always authority.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@bkudiess

bkudiess commented Aug 6, 2026

Copy link
Copy Markdown
Owner Author

Closing this fork-only draft because the change is being opened against the upstream repository.

@bkudiess bkudiess closed this Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.