diff --git a/.agents/skills/openclaw-proof-validation/SKILL.md b/.agents/skills/openclaw-proof-validation/SKILL.md new file mode 100644 index 000000000..098aeb71e --- /dev/null +++ b/.agents/skills/openclaw-proof-validation/SKILL.md @@ -0,0 +1,80 @@ +--- +name: openclaw-proof-validation +description: "Plan and collect OpenClaw Windows validation/proof: tests, rubber-duck review, UI evidence, MCP output, and gateway runtime proof." +--- + +# OpenClaw Proof and Validation + +Use for changes that affect tray UX, Settings, onboarding, chat/canvas, Command Center, Windows node capabilities, local MCP, gateway connection/pairing, permissions, diagnostics, or agent-facing instructions. + +## Rules + +- Required automated/focused tests are mandatory. Do not ask to skip them. +- Prefer isolated tray data so proof does not mutate `%APPDATA%\OpenClawTray`. +- Computer-use is usually a batched closeout proof pass, not a continuous dev-loop tool. Mid-development use is fine when explicitly requested or needed to unblock work; ask first whether to run it or provide manual screenshot/output steps. +- Local MCP is part of every Windows node command contract: command discovery and invocation must work through `winnode` or raw MCP JSON-RPC. +- Rubber-duck review is required before PR publication for non-trivial UI/MCP/node-command/setup/pairing/security/permissions/diagnostics work; it is also useful mid-development when extra design/testing validation is requested. +- Report blockers explicitly. Do not turn missing UI, MCP, gateway, camera, screen, or permission proof into success-shaped wording. + +## Required validation + +```powershell +$env:OPENCLAW_REPO_ROOT = (Get-Location).Path +.\build.ps1 +dotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csproj --no-restore +dotnet test .\tests\OpenClaw.Tray.Tests\OpenClaw.Tray.Tests.csproj --no-restore +``` + +Fresh worktrees may need a first run without `--no-restore`, or a project build first, so tests do not no-op before `bin\` exists. + +For `winnode`, command descriptions, or new/renamed node commands, also run: + +```powershell +dotnet test .\tests\OpenClaw.WinNode.Cli.Tests\OpenClaw.WinNode.Cli.Tests.csproj --no-restore +``` + +## Proof checklist + +| Surface | Proof to collect | +|---|---| +| UI / WinUI | Launch `.\run-app-local.ps1 -Isolated`, exercise the changed path with computer-use or developer-provided screenshots/output, and include visible evidence or blocker. If the developer captures manually, provide exact steps and confirm screenshot/artifact links resolve after updating the PR body. | +| Local MCP | Enable **Local MCP Server**, run `winnode --list-tools`, then invoke the changed command with `winnode --command --params ''`. | +| Raw MCP HTTP | For protocol/server-shape changes, paste JSON-RPC `tools/list` and `tools/call` responses from `http://127.0.0.1:8765/`. | +| Gateway path | When relevant and available, prove `openclaw nodes invoke --command --params ''`; otherwise state the gateway blocker. | +| Rubber-duck | Ask a rubber-duck reviewer to inspect the final implementation/proof plan; verify any finding before changing code. | + +For isolated tray runs, copy the data directory printed by `run-app-local.ps1 -Isolated` and set it before MCP proof commands: + +```powershell +$env:OPENCLAW_TRAY_DATA_DIR = '' +``` + +Raw token lookup: + +```powershell +$tokenPath = if ($env:OPENCLAW_TRAY_DATA_DIR) { + Join-Path $env:OPENCLAW_TRAY_DATA_DIR 'mcp-token.txt' +} else { + Join-Path $env:APPDATA 'OpenClawTray\mcp-token.txt' +} +$token = Get-Content $tokenPath -Raw +``` + +## New Windows node command checklist + +1. Register the command in the same `INodeCapability` path used by the gateway node. +2. Add/update `McpToolBridge.CommandDescriptions`. +3. Update `src/OpenClaw.WinNode.Cli/skill.md` with input shape, output shape, side effects, permissions, and examples. +4. Add/update capability, MCP bridge, `winnode`, and UI/gateway tests as applicable. +5. Prove discovery and invocation with `winnode` or raw MCP JSON-RPC. +6. Prove the gateway path when the behavior is gateway-mediated and a gateway is available. + +## PR proof package + +Before publishing or updating a PR, collect: + +1. `## Validation` with exact commands and pass/fail counts. +2. `## Real behavior proof` with current-head after-change evidence that directly shows the changed behavior: copied live output, screenshot/video, developer-provided screenshot, copied UI diagnostics, `winnode`, raw MCP JSON-RPC, gateway invoke output, redacted runtime log, or linked artifact. For UI changes, prefer screenshots/video of the active changed state, not only adjacent or empty UI. +3. PR body proof must stay in sync with current behavior: remove stale screenshots/claims after design changes and verify embedded image/artifact links resolve. +4. Rubber-duck notes for non-trivial UI/MCP-sensitive work, or why skipped. +5. `Not verified / blocked` notes for focused proof or unavailable dependencies. diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index ea618d645..8b7a3122f 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "gitversion.tool": { - "version": "6.7.0", + "version": "6.8.1", "commands": [ "dotnet-gitversion" ], diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..0dbd805de --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,89 @@ +## Summary + + + +- Problem: +- Why it matters: +- What changed: +- User impact: +- What did NOT change (scope boundary): + +## Change Type (select all) + + + +- [ ] Bug fix +- [ ] Feature +- [ ] Refactor +- [ ] Docs / instructions +- [ ] Tests / validation +- [ ] Security hardening +- [ ] Chore / infra + +## Scope (select all touched areas) + +- [ ] Tray / WinUI UX +- [ ] Windows node capability +- [ ] Local MCP / `winnode` +- [ ] Gateway / connection / pairing +- [ ] Setup / onboarding +- [ ] Permissions / privacy / security +- [ ] Tests / CI / docs + +## Linked Issue/PR + +- Closes # +- Related # +- [ ] Related to a bug or regression + +## Validation + + + +## Real behavior proof + + + +- Environment tested: +- PR head / commit tested: +- Exact steps or command run: +- Evidence after fix: +- Observed result: +- Screenshot/artifact links verified? (`Yes/No/N/A`) +- Not verified / blocked: + + + +## Security Impact (required) + +- New permissions/capabilities? (`Yes/No`) +- Secrets/tokens handling changed? (`Yes/No`) +- New/changed network calls? (`Yes/No`) +- Command/tool execution surface changed? (`Yes/No`) +- Data access scope changed? (`Yes/No`) +- If any `Yes`, explain risk + mitigation: + +## Compatibility / Migration + +- Backward compatible? (`Yes/No`) +- Config/env changes? (`Yes/No`) +- Migration needed? (`Yes/No`) +- If yes, exact upgrade steps: + +## Review Conversations + +- [ ] I replied to or resolved every bot review conversation I addressed in this PR. +- [ ] I left unresolved only conversations that still need reviewer or maintainer judgment. + +If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90182d08f..47c846885 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -91,7 +91,7 @@ jobs: - name: Cache NuGet packages continue-on-error: true - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }} @@ -275,7 +275,55 @@ jobs: -r win-x64 --verbosity normal --results-directory TestResults\TrayUI - --logger trx;LogFileName=OpenClaw.Tray.UITests.trx" + --logger trx;LogFileName=OpenClaw.Tray.UITests.trx + --filter Category!=Accessibility" + + # Accessibility Insights CI pass: scans each page in the real app process. + - name: Run Accessibility Tests (Axe.Windows) + id: a11y + run: > + dotnet test tests/OpenClaw.Tray.UITests + --no-build + -c Debug + -r win-x64 + --verbosity normal + --results-directory TestResults\Accessibility + --logger "trx;LogFileName=Accessibility.trx" + --filter Category=Accessibility + + - name: Accessibility test summary + if: always() && steps.a11y.outcome != 'skipped' + shell: pwsh + run: | + if ("${{ steps.a11y.outcome }}" -eq "failure") { + "### :x: Accessibility violations detected" >> $env:GITHUB_STEP_SUMMARY + "" >> $env:GITHUB_STEP_SUMMARY + "Axe.Windows scans found WCAG violations in one or more pages." >> $env:GITHUB_STEP_SUMMARY + "See the `Accessibility.trx` artifact for details." >> $env:GITHUB_STEP_SUMMARY + } else { + "### :white_check_mark: Accessibility scans passed" >> $env:GITHUB_STEP_SUMMARY + "" >> $env:GITHUB_STEP_SUMMARY + "All pages passed Axe.Windows accessibility validation." >> $env:GITHUB_STEP_SUMMARY + } + + - name: Verify DevBuild identity marker + shell: pwsh + run: | + dotnet build src/OpenClaw.Tray.WinUI -c Debug -r win-x64 -p:DevBuild=true --no-restore + $marker = Get-ChildItem -Path src\OpenClaw.Tray.WinUI\bin\Debug -Recurse -Filter app-identity.txt | + Where-Object { $_.FullName -like '*\win-x64\app-identity.txt' } | + Sort-Object LastWriteTimeUtc -Descending | + Select-Object -First 1 + if ($null -eq $marker) { + throw "Dev identity marker was not produced by the DevBuild." + } + + $identity = (Get-Content -LiteralPath $marker.FullName -Raw).Trim() + if ($identity -ne "dev") { + throw "Expected DevBuild identity marker 'dev' but found '$identity' at $($marker.FullName)." + } + + Write-Host "DevBuild identity marker verified at $($marker.FullName): $identity" - name: Upload Test Results if: always() @@ -293,16 +341,19 @@ jobs: needs: repo-hygiene if: ${{ !cancelled() }} runs-on: windows-latest - timeout-minutes: 25 + timeout-minutes: ${{ matrix.timeout_minutes }} strategy: fail-fast: false matrix: include: - name: setup-connect - filter: FullyQualifiedName~OpenClaw.E2ETests.Setup.SetupAndConnectTests + timeout_minutes: 45 + filter: "FullyQualifiedName~OpenClaw.E2ETests.Setup.SetupAndConnectTests|FullyQualifiedName~OpenClaw.E2ETests.Setup.MxcSetupAndConnectTests" - name: revocation-recovery + timeout_minutes: 25 filter: FullyQualifiedName~OpenClaw.E2ETests.Setup.RevocationAndRecoveryTests - name: network-recovery + timeout_minutes: 25 filter: FullyQualifiedName~OpenClaw.E2ETests.Setup.NetworkRecoveryTests steps: - name: Fail if repo hygiene failed @@ -323,7 +374,7 @@ jobs: - name: Cache NuGet packages continue-on-error: true - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }} @@ -366,6 +417,36 @@ jobs: Write-Error "E2E shard '${{ matrix.name }}' executed zero tests. Check OPENCLAW_RUN_E2E gating/filter before merging." exit 1 } + if ("${{ matrix.name }}" -eq "setup-connect") { + $mxcProofNames = @( + "RealGateway_SystemRun_ExecutesThroughWindowsNodeMxcSandbox", + "RealGateway_SystemRun_BlocksWritesToTrayDataDirectoryInMxcSandbox" + ) + + foreach ($mxcProofName in $mxcProofNames) { + $mxcProof = @($trx.TestRun.Results.UnitTestResult | Where-Object { $_.testName -like "*$mxcProofName*" }) | Select-Object -First 1 + if ($null -eq $mxcProof) { + Write-Error "E2E shard '${{ matrix.name }}' did not report the MXC proof test '$mxcProofName'. Check the setup-connect filter before merging." + exit 1 + } + + $mxcOutcome = [string]$mxcProof.outcome + if ($mxcOutcome -eq "Passed") { + Write-Host "MXC E2E proof passed: $mxcProofName" + } elseif ($mxcOutcome -eq "NotExecuted" -or $mxcOutcome -eq "Skipped") { + $mxcSkipReason = @($mxcProof.Output.ErrorInfo.Message, $mxcProof.Output.StdOut) | + Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | + Select-Object -First 1 + if ([string]::IsNullOrWhiteSpace($mxcSkipReason)) { + $mxcSkipReason = "skip reason was not present in the trx output" + } + Write-Warning "MXC E2E proof skipped: $mxcProofName; $mxcSkipReason" + } else { + Write-Error "MXC E2E proof '$mxcProofName' had unexpected outcome '$mxcOutcome'." + exit 1 + } + } + } - name: Upload E2E Test Results & Logs if: always() @@ -395,7 +476,7 @@ jobs: - name: Cache NuGet packages continue-on-error: true - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }} @@ -479,7 +560,7 @@ jobs: - name: Cache NuGet packages continue-on-error: true - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: ~/.nuget/packages key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', '**/Directory.Packages.props') }} diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 6b926f18f..a0a21cd0f 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -21,6 +21,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v7 - name: Install gh-aw extension - uses: github/gh-aw-actions/setup-cli@bee9622162d2319e68ef2594442f58c815f28d7f # v0.80.8 + uses: github/gh-aw-actions/setup-cli@3fac1cfa7a5a375a6a5eb9839178f6dad7adb60a # v0.82.2 with: version: v0.72.1 diff --git a/AGENTS.md b/AGENTS.md index 6c288035f..cc42d2f9d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,6 +13,8 @@ Required steps: 3. Run tray tests: - `dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore` +This is the required local closeout subset for agents. CI also builds and runs additional connection, setup, CLI, UI, accessibility, integration, and E2E suites; see `docs/TEST_COVERAGE.md` for the broader test inventory and `.github/workflows/ci.yml` for the workflow source of truth. + If a command fails: 1. Fix the issue. @@ -22,13 +24,51 @@ If a command fails: Notes: - If a build/test is blocked by an environmental lock (for example running executable locking output assemblies), stop/close the locking process and rerun. +- If validation is blocked by missing local Windows prerequisites, run `.\scripts\setup-dev.ps1` to install/verify developer and agent prerequisites, then rerun validation. Use `.\scripts\setup-dev.ps1 -CheckOnly` when you only need diagnostics. - **First-run gotcha**: `dotnet test --no-restore` silently no-ops in a fresh worktree where the test `bin/` doesn't exist yet (reports "Build succeeded in 0.5s" then exits 0 with no tests run). For first-run validation, either omit `--no-restore` OR run `dotnet build` on the test project first. Subsequent reruns honor `--no-restore` correctly. - In linked git worktrees, set `OPENCLAW_REPO_ROOT` to the worktree path before running tests that discover the repository root, for example: - - `$env:OPENCLAW_REPO_ROOT='D:\github\moltbot-windows-hub.'` + - `$env:OPENCLAW_REPO_ROOT='D:\github\openclaw-windows-node.'` - Tray tests must isolate `SettingsManager` from real user settings. Do not use `new SettingsManager()` in tests unless the test intentionally reads `%APPDATA%\OpenClawTray\settings.json`; pass a temp settings directory or set `OPENCLAW_TRAY_DATA_DIR` before the test process starts. - Prefer isolated worktrees for PR validation. Use `git-wt` for worktree workflows; `wt.exe` may resolve to WorkTrunk instead of Windows Terminal, so use the full Windows Terminal path when explicitly launching Terminal. - Do not claim completion without reporting validation results. +## Targeted Validation Paths + +Run the required validation above for every code change, then add the targeted path that matches the touched subsystem. + +### MXC / `system.run` / Windows node command execution + +When changing MXC sandboxing, `system.run`, exec approvals, Windows node command execution, gateway setup/connect E2E behavior, or files under `src\OpenClaw.Shared\Mxc`, run: + +```powershell +.\scripts\validate-mxc-e2e.ps1 +``` + +The script sets `OPENCLAW_RUN_E2E` and `OPENCLAW_RUN_MXC_E2E` itself, then runs the real WSL Gateway -> Windows node -> `system.run` MXC E2E proofs. It fails if the MXC proof skips. Use `-AllowSkip` only to document that the current host is not MXC-capable; do not report an `-AllowSkip` run as merge validation for MXC-related work. + +## UI, MCP, and PR Proof + +Use `.agents/skills/openclaw-proof-validation/SKILL.md` when a change touches tray UX, Settings, onboarding, chat/canvas, Command Center, Windows node capabilities, MCP, gateway connection/pairing, permissions, diagnostics, or agent-facing instructions. + +Policy: + +- Required automated/focused tests are mandatory; do not ask to skip them. +- Prefer computer-use as a batched closeout proof pass before PRs. If UI proof is useful mid-development, first ask whether to run computer-use now or provide manual steps so the developer can capture screenshots/output. +- For UI claims, collect current-head visible proof of the active changed state: computer-use screenshot/video, developer-provided screenshot, copied UI diagnostics, or an explicit blocker. +- If the developer captures UI proof manually, run or point them at the current isolated app, provide exact reproduction/capture steps, and verify any PR screenshot/artifact links after updating the PR body. +- For node/MCP changes, prove discovery and invocation with `winnode --list-tools` plus `winnode --command ...`, or raw MCP JSON-RPC `tools/list` plus `tools/call`. +- For gateway-mediated behavior, prove the real gateway path when available; otherwise state the blocker and keep MCP proof. +- Run rubber-duck review before PR publication for non-trivial UI, MCP, node-command, setup, pairing, security, permissions, or diagnostics changes. +- PRs should include `## Validation` and `## Real behavior proof`; proof must directly show the changed behavior from the current PR head. Fill `Not verified / blocked` for focused proof or unavailable dependencies. + +Every new Windows node call must be exposed, documented, and tested through MCP before completion: + +1. Register the capability/command in the tray node capability registry. +2. Add/update `McpToolBridge.CommandDescriptions`. +3. Update `src/OpenClaw.WinNode.Cli/skill.md`. +4. Add/update capability, MCP bridge, `winnode`, and UI/gateway tests as appropriate. +5. Run required validation plus `dotnet test .\tests\OpenClaw.WinNode.Cli.Tests\OpenClaw.WinNode.Cli.Tests.csproj --no-restore` when `winnode`, MCP output, or command docs change. + ## Architecture Context for New Agents Start with these docs before changing connection, pairing, node, MCP, or tray UX behavior: @@ -37,6 +77,19 @@ Start with these docs before changing connection, pairing, node, MCP, or tray UX - `docs/MCP_MODE.md` - local MCP server mode and the `EnableNodeMode` / `EnableMcpServer` matrix. - `docs/WINDOWS_NODE_TESTING.md` - Windows node capabilities, manual smokes, and gateway-dependent behavior. - `docs/ONBOARDING_WIZARD.md` - first-run setup flow, setup-code/bootstrap pairing, and test isolation. +- `docs/SETUP_ENGINE_REDESIGN.md` - setup pipeline, rollback/logging, Windows node context injection, and setup CLI contract. +- `docs/WSL_EXE_ARGV_PITFALL.md` - wsl.exe argv variable-expansion pitfall; required reading before adding any multi-line WSL script through `RunInWslAsync`. + +## Architecture Guardrails for Large Refactors + +`src\OpenClaw.Tray.WinUI\App.xaml.cs` and `src\OpenClaw.Tray.WinUI\Pages\ConnectionPage.xaml.cs` are active god-file reduction targets. When touching either file: + +- Prefer completing a real ownership transfer over moving code to partial classes. A new partial file is not progress unless it introduces a narrower owner, pure projection, policy, service, or tested seam. +- Keep `App` as the composition root. Shrink it by delegating cohesive behavior to focused services, but do not relocate startup ordering into another god object. +- Keep `ConnectionPage.xaml.cs` as the WinUI applicator until a pure row/plan/workflow seam exists. Do not move named-control setters into a presenter that just wraps the page. +- Add characterization tests before moving startup, credential, pairing, node/MCP, tray action, or direct-connect rollback behavior. Source-text contract tests are acceptable for WinUI-only seams, but prefer pure unit tests for policies and projections. +- Keep PRs small and reviewable: one seam per PR, with a clear invariant protected by tests. Stop and re-plan if a PR moves hundreds of lines without behavior coverage. +- In PR descriptions and handoffs, name the old owner, new owner, preserved invariant, and validation run so future agents do not reintroduce duplicate paths or grow new god objects. Important current facts: diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index f7f93754c..d60c18d99 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -18,14 +18,19 @@ A comprehensive guide for building, running, and contributing to the OpenClaw Wi - **.NET 10 SDK** - [Download here](https://dotnet.microsoft.com/download) - **Windows 10/11** - WinUI 3 and Windows App SDK require Windows 10 version 1903 or later +- **Node.js LTS with npm** - Required by the WinUI build to restore JavaScript build assets +- **Windows 10 SDK** - Required for WinUI builds - **WebView2 Runtime** - Usually pre-installed on Windows 10+ ([Manual download](https://developer.microsoft.com/microsoft-edge/webview2/)) - **Visual Studio 2022** (optional) - For easier development and debugging with WinUI 3 designer support +Run `.\scripts\setup-dev.ps1` from the repository root to install or verify local prerequisites with winget. Agents can use `.\scripts\setup-dev.ps1 -RunValidation` to prepare the worktree and run the required closeout validation. + ### For Testing -- **A running OpenClaw gateway instance** - The gateway provides the backend for chat, sessions, and notifications +- **A running OpenClaw gateway instance** - The gateway provides the backend for chat, sessions, and notifications when validating gateway-mediated flows - Default gateway URL: `ws://localhost:18789` - You'll need a valid authentication token from your OpenClaw instance +- **Local MCP Server** - Windows node capabilities can also be validated without a gateway by enabling Local MCP Server in the tray Settings UI and using `winnode` ## Project Structure @@ -39,14 +44,24 @@ openclaw-windows-hub/ │ │ ├── Models.cs # Data models (SessionInfo, ChannelHealth, etc.) │ │ └── IOpenClawLogger.cs # Logging interface │ │ +│ ├── OpenClaw.Connection/ # Gateway registry, credentials, connection manager +│ │ │ ├── OpenClaw.Chat/ # Native chat model and reducer │ │ ├── ChatModels.cs # Threads, entries, events, provider contract │ │ └── ChatTimelineReducer.cs # Timeline state transitions │ │ +│ ├── OpenClaw.Cli/ # WebSocket connect/send/probe validator +│ │ +│ ├── OpenClaw.WinNode.Cli/ # winnode local MCP/Windows-node CLI +│ │ +│ ├── OpenClaw.SetupEngine/ # Local WSL gateway setup and setup-code support +│ │ +│ ├── OpenClaw.SetupEngine.UI/ # WinUI setup wizard pages hosted by the tray app +│ │ │ ├── OpenClawTray.FunctionalUI/ # Small in-repo declarative WinUI helper │ │ └── FunctionalUI.cs # Components, hooks, elements, host control │ │ -│ ├── OpenClaw.Tray.WinUI/ # WinUI 3 system tray application (primary) +│ └── OpenClaw.Tray.WinUI/ # WinUI 3 system tray application (primary) │ │ ├── App.xaml.cs # Main application, tray icon, gateway connection │ │ ├── Services/ # Settings, logging, hotkeys, deep links │ │ ├── Windows/ # UI windows (Settings, WebChat, Status, etc.) @@ -54,11 +69,15 @@ openclaw-windows-hub/ │ │ └── Helpers/ # Icon generation, utilities │ │ ├── tests/ -│ ├── OpenClaw.Shared.Tests/ # Unit tests for shared library -│ └── OpenClaw.Tray.Tests/ # Tests for tray helpers (menu, settings, deep links) -│ -├── tools/ -│ └── icongen/ # Icon generation tool +│ ├── OpenClaw.Shared.Tests/ # Unit tests for shared library/capabilities/MCP +│ ├── OpenClaw.Connection.Tests/ # Gateway registry and connection manager tests +│ ├── OpenClaw.Tray.Tests/ # Tests for tray helpers (menu, settings, deep links) +│ ├── OpenClaw.WinNode.Cli.Tests/ # winnode CLI contract tests +│ ├── OpenClaw.SetupEngine.Tests/ # Setup engine tests +│ ├── OpenClaw.Tray.UITests/ # Native WinUI/A2UI UI tests +│ ├── OpenClawTray.FunctionalUI.Tests/ # FunctionalUI smoke tests +│ ├── OpenClaw.Tray.IntegrationTests/ # Real-process tray/MCP integration tests +│ └── OpenClaw.E2ETests/ # Gateway-mediated setup/connect E2E suites │ ├── .github/workflows/ │ └── ci.yml # GitHub Actions CI/CD workflow @@ -71,9 +90,11 @@ openclaw-windows-hub/ ### Project Dependencies ``` -OpenClaw.Tray.WinUI ──depends on──▶ OpenClaw.Shared -OpenClaw.Shared.Tests ──tests──▶ OpenClaw.Shared -OpenClaw.Tray.Tests ──tests──▶ OpenClaw.Shared +OpenClaw.Tray.WinUI ──depends on──▶ OpenClaw.Shared + OpenClaw.Connection + OpenClaw.Chat + OpenClaw.SetupEngine.UI +OpenClaw.WinNode.Cli ──depends on──▶ OpenClaw.Shared +OpenClaw.SetupEngine.UI ──wraps──▶ OpenClaw.SetupEngine +OpenClaw.SetupEngine ──supports──▶ local WSL gateway setup +OpenClaw.*.Tests ──test──▶ corresponding shared, connection, tray, setup, and CLI surfaces ``` ### Key Subsystems @@ -81,6 +102,7 @@ OpenClaw.Tray.Tests ──tests──▶ OpenClaw.Shared | Subsystem | Location | Purpose | |-----------|----------|---------| | **Gateway Communication** | `OpenClaw.Shared/OpenClawGatewayClient.cs` | WebSocket client with protocol v3, reconnect/backoff logic | +| **Connection Management** | `OpenClaw.Connection/` | Gateway registry, credential precedence, pairing, tunnels, and reconnect policy | | **Notification System** | `OpenClaw.Tray.WinUI/App.xaml.cs` | Event routing, toast notifications, classification | | **WebView2 Integration** | `OpenClaw.Tray.WinUI/Windows/ChatWindow.xaml.cs` | Embedded chat panel with lifecycle management | | **Tray Icon Management** | `OpenClaw.Tray.WinUI/Helpers/IconHelper.cs` | GDI handle management, dynamic icon generation | @@ -94,11 +116,10 @@ OpenClaw.Tray.Tests ──tests──▶ OpenClaw.Shared From the repository root: ```bash -dotnet restore -dotnet build +./build.ps1 ``` -This builds all projects (shared library, tray app, setup engine, and CLI tools). +This restores prerequisites as needed and builds the shared library, tray app, setup engine, and CLI tools with the required Windows runtime identifiers. ### Build Individual Projects @@ -109,7 +130,7 @@ dotnet build src/OpenClaw.Shared **Tray App (WinUI):** ```bash -dotnet build src/OpenClaw.Tray.WinUI +dotnet build src/OpenClaw.Tray.WinUI -r win-x64 ``` ### Platform and Architecture Notes @@ -136,7 +157,7 @@ dotnet build The WinUI Tray app is Windows-only but can be built on Linux using: ```bash -dotnet build -p:EnableWindowsTargeting=true +dotnet build src/OpenClaw.Tray.WinUI -r win-x64 -p:EnableWindowsTargeting=true ``` ### Running in Debug Mode @@ -150,13 +171,13 @@ dotnet build -p:EnableWindowsTargeting=true #### Command Line ```bash -dotnet run --project src/OpenClaw.Tray.WinUI +dotnet run --project src/OpenClaw.Tray.WinUI -r win-x64 ``` For verbose output: ```bash -dotnet run --project src/OpenClaw.Tray.WinUI -c Debug +dotnet run --project src/OpenClaw.Tray.WinUI -c Debug -r win-x64 ``` ### Publishing (Self-Contained) @@ -186,6 +207,26 @@ Use the local helper to build unsigned installer EXEs without waiting for CI: `-Fast` uses ZIP/no-solid compression for quick local iteration. CI release builds keep the default LZMA solid compression and Azure signing. +#### Dev identity and side-by-side installs + +Release identity is the default for every configuration. Use `-DevBuild` on `build.ps1` or `-Dev` on `run-app-local.ps1` when you explicitly want the side-by-side dev identity: + +```powershell +.\build.ps1 -Project WinUI -DevBuild +.\run-app-local.ps1 -Dev -Isolated +``` + +`-DevBuild` passes `-p:DevBuild=true` to the WinUI project and produces the dev app identity marker that CI verifies in the **Verify DevBuild identity marker** step. `installer.iss` also accepts `/DDevBuild=1` for side-by-side dev installers; `.\scripts\build-inno-local.ps1 -Dev` wires that flag for local installer iteration. + +#### Onboarding and setup workflow helpers + +The first-run Windows gateway onboarding wizard lives in `OpenClaw.SetupEngine.UI` and is hosted by `OpenClaw.Tray.WinUI`; see [docs/ONBOARDING_WIZARD.md](docs/ONBOARDING_WIZARD.md) for the page flow. The setup pipeline itself is documented in [docs/SETUP_ENGINE_REDESIGN.md](docs/SETUP_ENGINE_REDESIGN.md), including the Windows node context step that injects agent instructions into the WSL workspace. + +Useful local scripts: + +- `.\scripts\dev-reset-rebuild-launch.ps1` resets tray data, rebuilds, and optionally launches the app; add `-WipeWslDistro` for a full local WSL gateway reset. +- `.\scripts\validate-mxc-e2e.ps1` runs the formal WSL Gateway -> Windows node -> `system.run` MXC proof path for MXC-sensitive changes. + ## Architecture Overview ### Native chat surface (FunctionalUI + OpenClaw.Chat) @@ -200,9 +241,9 @@ settings-controlled fallback. **Layering:** ``` -src/OpenClaw.Tray.WinUI/Chat/ OpenClawChatTimeline · OpenClawComposer · OpenClawSessionHeader +src/OpenClaw.Tray.WinUI/Chat/ ChatTimeline · ChatComposer · OpenClawSessionHeader OpenClawChatDataProvider (adapts OpenClawGatewayClient → IChatDataProvider) - OpenClawChatRoot (FunctionalUI component composing the chat surface) + ChatRoot (FunctionalUI component composing the chat surface) FunctionalChatHostExtensions (mounts FunctionalUI into a XAML ) IChatGatewayBridge (testability seam over OpenClawGatewayClient) ▲ depends on @@ -424,9 +465,28 @@ Sensitive data (authentication tokens) are never logged. ## Testing +Required agent validation lives in [AGENTS.md](AGENTS.md). For changes touching +tray UX, Settings, onboarding, chat/canvas, Command Center, Windows node +capabilities, local MCP, gateway pairing/connection, permissions, or +diagnostics, use the repo-local skill +`.agents/skills/openclaw-proof-validation/SKILL.md`: run the build/tests, +validate local MCP with `winnode --list-tools` plus the changed command, run +rubber-duck review for non-trivial changes, then launch the tray from this +worktree and drive the changed UI with computer-use / desktop automation as one +batched closeout pass before PR publication. Mid-development rubber-duck, +computer-use, or MCP validation is also appropriate when explicitly requested or +needed to unblock the work; agents should ask whether to run computer-use or +provide manual UI proof steps, while still enforcing required automated tests. + +PRs should include `## Validation` and `## Real behavior proof` sections. Paste concrete +after-change output, visible UI evidence for visual changes, `winnode` output or +raw MCP server JSON-RPC output for node commands, and gateway invoke output for +gateway-mediated behavior when available; the default PR template includes these +prompts. + ### Running Unit Tests -Two test projects cover the shared library and tray helpers: +The repository has multiple unit, UI, integration, and E2E test projects. Use [docs/TEST_COVERAGE.md](docs/TEST_COVERAGE.md) as the inventory of record. ```bash # Run local-dev tests. E2E is intentionally excluded from the solution and @@ -441,9 +501,10 @@ dotnet test --filter "FullyQualifiedName~AgentActivityTests" ``` **Test Coverage:** -- ✅ **1182 tests** in `OpenClaw.Shared.Tests` — models, gateway client, exec approvals, capabilities, URL helpers, notification categorization, shell quoting, MCP, device identity, and WinNode client coverage -- ✅ **388 tests** in `OpenClaw.Tray.Tests` — settings round-trip, deep link parsing, onboarding state, setup code decoder, gateway health/chat helpers, security validation, wizard step parsing, gateway discovery, localization validation -- ✅ All tests are pure unit tests (no network, no file system, no external dependencies) +- `OpenClaw.Shared.Tests` covers models, gateway client behavior, capabilities, URL helpers, notification categorization, shell quoting, MCP, device identity, and WinNode client contracts. +- `OpenClaw.Tray.Tests` covers settings isolation, deep link parsing, onboarding state, setup code decoding, gateway health/chat helpers, security validation, wizard step parsing, gateway discovery, localization, and tray UI helpers. +- Additional projects cover connection management, setup engine behavior, `winnode`, FunctionalUI, native UI/A2UI, integration, and gateway-mediated E2E flows. +- See [docs/TEST_COVERAGE.md](docs/TEST_COVERAGE.md) for current method counts, runtime totals, and which lanes require network, WSL, real-process, or desktop prerequisites. See [tests/OpenClaw.Shared.Tests/README.md](tests/OpenClaw.Shared.Tests/README.md) for detailed test documentation. diff --git a/Directory.Build.props b/Directory.Build.props index 50095e8b8..024ed3aaa 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ 2.2.0 - 10.0.28000.1839 + 10.0.28000.2270 diff --git a/README.md b/README.md index a2d4870d7..3424a7162 100644 --- a/README.md +++ b/README.md @@ -21,27 +21,54 @@ This monorepo contains the Windows hub, shared client libraries, and CLI utiliti | Project | Description | |---------|-------------| | **OpenClaw.Tray.WinUI** | System tray application (WinUI 3) for quick access to OpenClaw | -| **OpenClaw.Shared** | Shared gateway client library | +| **OpenClaw.Connection** | Gateway registry, credential resolution, and connection manager | +| **OpenClaw.Shared** | Shared gateway client library, capabilities, and MCP bridge | +| **OpenClaw.Chat** | Native chat model and timeline reducer | | **OpenClaw.Cli** | CLI validator for WebSocket connect/send/probe using tray settings | +| **OpenClaw.WinNode.Cli** | `winnode` CLI for invoking local Windows node/MCP capabilities | +| **OpenClaw.SetupEngine** | Local gateway setup, WSL installation, and setup-code support | +| **OpenClaw.SetupEngine.UI** | WinUI setup wizard pages hosted by the tray app | +| **OpenClawTray.FunctionalUI** | In-repo declarative WinUI helper used by native chat and newer UI surfaces | ## 🚀 Quick Start > **End-user installer?** Download the latest stable x64 or ARM64 installer from the [OpenClaw Windows docs](https://docs.openclaw.ai/platforms/windows), or see [docs/SETUP.md](docs/SETUP.md) for step-by-step installation (no build required). > > **Managed WSL gateway?** Local setup creates a locked-down app-owned `OpenClawGateway` distro. See [docs/WSL_GATEWAY_ADMIN.md](docs/WSL_GATEWAY_ADMIN.md) for editing `openclaw.json` as the `openclaw` user and using root for protected-file administration. +> +> **Operator or node?** Start with [Operator and node concepts](docs/OPERATOR_NODE_CONCEPTS.md) for the beginner-facing glossary of gateway, operator, node, pairing, reapproval, and allowlisted node capabilities. -Direct downloads from the latest OpenClaw release: +Direct downloads from the latest OpenClaw Windows release: -- [OpenClawCompanion-Setup-x64.exe](https://github.com/openclaw/openclaw/releases/latest/download/OpenClawCompanion-Setup-x64.exe) -- [OpenClawCompanion-Setup-arm64.exe](https://github.com/openclaw/openclaw/releases/latest/download/OpenClawCompanion-Setup-arm64.exe) -- [OpenClawCompanion-SHA256SUMS.txt](https://github.com/openclaw/openclaw/releases/latest/download/OpenClawCompanion-SHA256SUMS.txt) +- [OpenClawCompanion-Setup-x64.exe](https://github.com/openclaw/openclaw-windows-node/releases/latest/download/OpenClawCompanion-Setup-x64.exe) +- [OpenClawCompanion-Setup-arm64.exe](https://github.com/openclaw/openclaw-windows-node/releases/latest/download/OpenClawCompanion-Setup-arm64.exe) +- [OpenClawCompanion-SHA256SUMS.txt](https://github.com/openclaw/openclaw-windows-node/releases/latest/download/OpenClawCompanion-SHA256SUMS.txt) ### Prerequisites - Windows 10 (20H2+) or Windows 11 - .NET 10.0 SDK - https://dotnet.microsoft.com/download/dotnet/10.0 +- Node.js LTS with npm (for WinUI build assets) - Windows 10 SDK (for WinUI build) - install via Visual Studio or standalone - WebView2 Runtime - pre-installed on modern Windows, or get from https://developer.microsoft.com/microsoft-edge/webview2 +### Developer / Agent Setup + +Use the setup script to install or verify local Windows build prerequisites: + +```powershell +# Install missing prerequisites with winget, trust the checkout, and verify setup +.\scripts\setup-dev.ps1 + +# Check only; do not install packages or change git safe.directory +.\scripts\setup-dev.ps1 -CheckOnly + +# Install/verify prerequisites without adding the checkout to git safe.directory +.\scripts\setup-dev.ps1 -NoTrustRepository + +# Setup and run the required build/test validation +.\scripts\setup-dev.ps1 -RunValidation +``` + ### Build Use the build script to check prerequisites and build: @@ -84,6 +111,9 @@ dotnet build src/OpenClaw.Tray.WinUI -r win-x64 -p:PackageMsix=true # x64 MSI # Run isolated from your normal tray settings so multiple worktrees can run together .\run-app-local.ps1 -Isolated +# Opt into side-by-side dev identity (separate mutex, protocol, gateway distro, and port) +.\run-app-local.ps1 -Dev -Isolated + # Alpha update testing from a Release build .\run-app-local.ps1 -Configuration Release -Isolated -UpdateChannel alpha @@ -118,7 +148,7 @@ dotnet run --project src/OpenClaw.Cli -- --url ws://127.0.0.1:18789 --token "$null + if ($LASTEXITCODE -ne 0 -or $insideWorkTree -ne "true") { + Write-Error "Git metadata not found. GitVersion requires a git clone with full history." + Write-Info "Clone the repository with git, then rerun .\build.ps1." + $script:issues += "Repository is missing git metadata required by GitVersion" + return + } + + $isShallow = & git -C $repoRoot rev-parse --is-shallow-repository 2>$null + if ($LASTEXITCODE -eq 0 -and $isShallow -eq "true") { + Write-Error "Repository is a shallow clone. GitVersion requires full git history." + Write-Info "Run this once, then retry the build:" + Write-Info "git fetch --unshallow --tags origin" + $script:issues += "Repository is shallow; GitVersion requires full history" + } +} + Write-Host @" 🦞 OpenClaw Windows Hub - Build Script @@ -143,7 +176,7 @@ Write-Host @" Write-Header "Checking Prerequisites" # Check OS -if ($env:OS -ne "Windows_NT") { +if (-not (Test-WindowsHost)) { Write-Error "This project requires Windows" exit 1 } @@ -191,6 +224,7 @@ if (-not $git) { } Ensure-GitVersionRepositoryTrust + Ensure-GitVersionRepositoryHistory } # Check Node.js + npm (WinUI build runs `npm ci` to restore @microsoft/mxc-sdk @@ -219,11 +253,23 @@ if (-not $nodeVersion) { # Check Windows SDK (for WinUI) $windowsSdkPath = "${env:ProgramFiles(x86)}\Windows Kits\10\Include" if (Test-Path $windowsSdkPath) { - $sdkVersions = Get-ChildItem $windowsSdkPath -Directory | Select-Object -ExpandProperty Name | Sort-Object -Descending - Write-Success "Windows SDK: $($sdkVersions[0])" + $sdkVersions = @( + Get-ChildItem $windowsSdkPath -Directory | + Where-Object { $_.Name -match "^\d+\.\d+\.\d+\.\d+$" } | + Sort-Object { [version]$_.Name } -Descending | + Select-Object -ExpandProperty Name + ) + + if ($sdkVersions.Count -gt 0) { + Write-Success "Windows SDK: $($sdkVersions[0])" + } else { + Write-Warning "Windows 10 SDK not found (needed for WinUI build)" + Write-Info "Install via Visual Studio Installer, standalone SDK, or: winget install --id Microsoft.WindowsSDK.10.0.26100 -e" + $issues += "Windows 10 SDK not detected" + } } else { Write-Warning "Windows 10 SDK not found (needed for WinUI build)" - Write-Info "Install via Visual Studio Installer or standalone SDK" + Write-Info "Install via Visual Studio Installer, standalone SDK, or: winget install --id Microsoft.WindowsSDK.10.0.26100 -e" $issues += "Windows 10 SDK not detected" } @@ -282,7 +328,10 @@ if ($issues.Count -gt 0) { Write-Header "Building Projects ($Configuration)" # Detect runtime identifier based on architecture -$rid = if ($arch -eq "ARM64") { "win-arm64" } else { "win-x64" } +$rid = switch ($arch) { + "ARM64" { "win-arm64" } + default { "win-x64" } +} Write-Info "Runtime identifier: $rid" $buildResults = @{} @@ -310,6 +359,9 @@ function Build-Project($name, $path, $useRid = $false) { if ($useRid) { $dotnetArgs += @("-r", $rid) } + if ($DevBuild -and ($name -eq "WinUI" -or $name -eq "Tray")) { + $dotnetArgs += "-p:DevBuild=true" + } $result = Invoke-DotNetCaptured $dotnetArgs $exitCode = $LASTEXITCODE @@ -407,9 +459,11 @@ if ($failCount -eq 0) { if ($winUITargetFramework) { $winUIOutputDirectory = ".\$winUIProjectDirectory\bin\$Configuration\$winUITargetFramework\$rid" $winUIManifestPath = ".\$winUIProjectDirectory\Package.appxmanifest" - Write-Host " WinUI: .\run-app-local.ps1 -NoBuild" -ForegroundColor White - Write-Host " Isolated: .\run-app-local.ps1 -NoBuild -Isolated" -ForegroundColor White - Write-Host " WinApp: .\run-app-local.ps1 -NoBuild -UseWinApp" -ForegroundColor White + $runIdentitySwitch = if ($DevBuild) { " -Dev" } else { "" } + Write-Host " WinUI: .\run-app-local.ps1 -NoBuild$runIdentitySwitch" -ForegroundColor White + Write-Host " Isolated: .\run-app-local.ps1 -NoBuild -Isolated$runIdentitySwitch" -ForegroundColor White + Write-Host " Dev: .\run-app-local.ps1 -Dev" -ForegroundColor White + Write-Host " WinApp: .\run-app-local.ps1 -NoBuild -UseWinApp$runIdentitySwitch" -ForegroundColor White Write-Host " Direct launch is default. -UseWinApp runs: winapp run `"$winUIOutputDirectory`" --manifest `"$winUIManifestPath`" --executable `"OpenClaw.Tray.WinUI.exe`" --debug-output" -ForegroundColor DarkGray } else { Write-Warning "Unable to determine WinUI target framework from $winUIProjectPath" diff --git a/docs/A2UI_NATIVE_WINUI.md b/docs/A2UI_NATIVE_WINUI.md index 4ed6f23cc..c37ba9eeb 100644 --- a/docs/A2UI_NATIVE_WINUI.md +++ b/docs/A2UI_NATIVE_WINUI.md @@ -1,22 +1,24 @@ # Native WinUI A2UI Canvas — Design Spec -> **Status:** Draft / proposal -> **Audience:** Contributors implementing a native A2UI renderer for the Windows node +> **Status:** Implemented; historical design rationale +> **Audience:** Contributors maintaining the native A2UI renderer for the Windows node > **Target version:** A2UI v0.8 (parity with current openclaw clients), with a v0.9 migration path +The native WinUI renderer is implemented under `src\OpenClaw.Tray.WinUI\A2UI\`. This file preserves the original design rationale; the current source of truth for protocol and component details lives in `docs\a2ui\` (`README.md`, `protocol.md`, `components.md`, and grading notes). Phase 4 / A2UI v0.9 migration has not started. + ## 1. Motivation -Today the Windows node renders A2UI by hosting a WebView2 control (`CanvasWindow`) that navigates to an HTTP page served by the openclaw gateway at `/__openclaw__/a2ui/`. That page bundles `@a2ui/lit` and openclaw's bridge JS. Pushed messages travel `agent → gateway → node (canvas.a2ui.push) → WebView2 → window.__a2ui.receive(msg)`. +Before the native renderer landed, the Windows node rendered A2UI by hosting a WebView2 control (`CanvasWindow`) that navigated to an HTTP page served by the openclaw gateway at `/__openclaw__/a2ui/`. That page bundled `@a2ui/lit` and openclaw's bridge JS. Pushed messages traveled `agent → gateway → node (canvas.a2ui.push) → WebView2 → window.__a2ui.receive(msg)`. -That works, but it has costs: +That worked, but it had costs: -- **Hard gateway dependency.** A node running in MCP-only mode (no gateway connection) silently drops A2UI pushes — `OnCanvasA2UIPush` bails when `_a2uiHostUrl` is null. The renderer code physically lives at the gateway. +- **Hard gateway dependency.** A node running in MCP-only mode (no gateway connection) could silently drop A2UI pushes because the WebView2 renderer code lived at the gateway. - **WebView2 surface area.** Drag/drop, IME, accessibility, focus, DPI, and keyboard shortcuts inherit WebView2 quirks instead of XAML's native behavior. The canvas always feels like an embedded browser. - **Bootstrapping latency.** Each cold start has to ensure WebView2 is ready, navigate, and wait for `window.__a2ui` to register before any message can be delivered (`EnsureA2UIHostAsync` + `ensureA2uiReady` polling). - **Theming drift.** WinUI windows around the canvas use Mica/Fluent; the canvas uses Lit components styled with CSS. Achieving consistent visuals requires duplicate theme work. - **Hardening.** Surface area for arbitrary script execution remains larger than necessary for what is fundamentally a declarative UI tree. -A native WinUI renderer renders A2UI surfaces directly into XAML — no WebView, no HTTP host, no JS bridge. The node becomes self-contained: it can render A2UI whether it's connected to a gateway, an MCP client, or both. +The implemented native WinUI renderer renders A2UI surfaces directly into XAML — no WebView, no HTTP host, no JS bridge. The node is self-contained: it can render A2UI whether it's connected to a gateway, an MCP client, or both. ## 2. Goals & non-goals @@ -267,12 +269,14 @@ Mirror what `CanvasCapability` already logs: ## 13. Phasing +This table is historical. Phases 0-3 are now implemented by the native renderer path; no `--canvas=web` coexistence flag shipped. Phase 4 / v0.9 migration has not started. + | Phase | Scope | Exit criteria | |---|---|---| | **0 — Spike** | `Text`, `Column`, `Button` only; one surface; no data model | Single button click round-trips to agent | | **1 — Catalog parity** | All v0.8 standard catalog types; data model + bindings; modal/tabs | Full conformance fixtures pass | | **2 — Polish** | Theming, transitions, focus management, accessibility (Narrator), keyboard nav | A11y audit clean; UX review against Lit version | -| **3 — Coexistence** | Native window default; WebView2 path retained behind `--canvas=web` flag for parity testing | No regressions in WebView2 path | +| **3 — Native default** | Native window default for A2UI rendering | Native path covers the v0.8 surface without the WebView2 host | | **4 — v0.9 migration** | Bidirectional messages, modular schemas, prompt-first | Tracks Google A2UI v0.9 release | ## 14. Open questions diff --git a/docs/ACCESSIBILITY.md b/docs/ACCESSIBILITY.md new file mode 100644 index 000000000..a994c4959 --- /dev/null +++ b/docs/ACCESSIBILITY.md @@ -0,0 +1,28 @@ +# Accessibility validation + +OpenClaw Companion treats accessibility as a CI quality gate for the WinUI app. The Build and Test workflow runs real-process Axe.Windows scans against the tray UI test project after the normal native UI tests. + +## What CI enforces + +The `.github\workflows\ci.yml` **Run Accessibility Tests (Axe.Windows)** step runs: + +```powershell +dotnet test tests\OpenClaw.Tray.UITests --no-build -c Debug -r win-x64 --filter Category=Accessibility +``` + +Those tests launch the app in a real Windows desktop process and scan pages for WCAG violations through Axe.Windows. Failures are summarized in the GitHub Actions step summary and written to `Accessibility.trx`. + +## Running locally + +From the repository root: + +```powershell +dotnet build tests\OpenClaw.Tray.UITests -c Debug -r win-x64 +dotnet test tests\OpenClaw.Tray.UITests -c Debug -r win-x64 --no-build --filter Category=Accessibility +``` + +Run this lane for UI changes that add or modify pages, dialogs, controls, focus behavior, labels, contrast-sensitive visuals, or keyboard navigation. + +## Relationship to other validation + +Accessibility scans do not replace the required agent closeout validation in `AGENTS.md`. They are an additional focused lane for WinUI accessibility work and a formal CI gate documented in `docs\TEST_COVERAGE.md`. diff --git a/docs/CONNECTION_ARCHITECTURE.md b/docs/CONNECTION_ARCHITECTURE.md index e0b19c00d..63629b340 100644 --- a/docs/CONNECTION_ARCHITECTURE.md +++ b/docs/CONNECTION_ARCHITECTURE.md @@ -69,17 +69,21 @@ Inbound chat and agent timeline events must include the gateway's canonical `ses ## Startup wiring (App.xaml.cs) ``` -1. Create GatewayRegistry(dataDir) -2. Create CredentialResolver(identityReader) -3. Create GatewayClientFactory() -4. Create NodeConnector(logger) -5. Create SshTunnelManager(tunnelService, logger) -6. Create GatewayConnectionManager(resolver, factory, registry, ..., - nodeConnector, tunnelManager) -7. Subscribe to StateChanged → update tray icon + hub window -8. Subscribe to OperatorClientChanged → wire/unwire 25+ data event handlers -9. Subscribe to NodeConnector.ClientCreated → NodeService.AttachClient -10. Call ConnectAsync() → connects to active gateway +1. Create GatewayRegistry(SettingsManager.SettingsDirectoryPath) +2. Load gateway registry from gateways.json +3. Create CredentialResolver(DeviceIdentityFileReader.Instance) +4. Create GatewayClientFactory() +5. Create ConnectionDiagnostics() +6. Create NodeConnector(logger, diagnostics) +7. Wire NodeConnector.ClientCreated → NodeService.AttachClient +8. Create SshTunnelService(logger) +9. Create GatewayConnectionManager(resolver, factory, registry, logger, + identityStore, nodeConnector, node mode flag, + diagnostics, tunnelService) +10. Subscribe to OperatorClientChanged → wire/unwire 25+ data event handlers +11. Subscribe to StateChanged → update tray icon + hub window +12. Ensure NodeService exists before gateway initialization +13. Call InitializeGatewayClient() → connects to active gateway ``` Settings changes are classified by `SettingsChangeClassifier.Classify()` which compares `ConnectionSettingsSnapshot` before/after to determine the minimum reconnect action: @@ -114,7 +118,10 @@ Idle → Connecting → Connected | Connected | Error/Rejected | Degraded | | Connected | PairingRequired | PairingRequired | | Connected | Connecting | Connecting | -| Connected | Disabled/Off | Connected | +| Connected | Idle while Node mode is intended | Degraded | +| Connected | Disabled/Off | Ready | + +`GatewayConnectionSnapshot.NodeConnectionIntended` records the Node mode intent used by the manager's state machine. If Node mode is enabled but node startup is skipped, blocked, or missing a node credential, the manager publishes a blocked node snapshot (`NodeState=Error`, `NodeError=...`) instead of leaving the node idle and letting tray surfaces report a healthy connection. ## Gateway registry and persistence @@ -126,7 +133,7 @@ Idle → Connecting → Connected %APPDATA%\OpenClawTray\gateways\\device-key-ed25519.json — keypair + tokens ``` -Each `GatewayRecord` contains: `Id`, `Url`, `FriendlyName`, `SharedGatewayToken`, `BootstrapToken`, `LastConnected`, `SshTunnel` config, and an `IdentityDirName`. +Each `GatewayRecord` contains: `Id`, `Url`, `FriendlyName`, `SharedGatewayToken`, `BootstrapToken`, `LastConnected`, `SshTunnel` config, `IsLocal`, `RequiresV2Signature`, `SetupManagedDistroName`, and `BrowserControlPort`. The `IdentityDirName` property is computed from `Id`. `SettingsManager` still owns general tray settings (node mode, MCP mode, SSH tunnel toggles, notifications, UI preferences). It may read legacy `Token` / `BootstrapToken` JSON fields into memory for migration, but save must not write those legacy credential fields back. @@ -143,6 +150,13 @@ The invariant is that a paired device token always wins. Do not downgrade a pair **`CredentialResolver`** implements the precedence for WebSocket connections (operator and node roles). +Node credential precedence follows the same invariant with a distinct stored token: + +1. **Stored node device token** in the per-gateway identity directory. +2. **`GatewayRecord.SharedGatewayToken`** — shared token fallback when no paired node token exists. +3. **`GatewayRecord.BootstrapToken`** — one-time setup, limited scopes. +4. **No credential** — caller logs and skips node client init. + **`InteractiveGatewayCredentialResolver`** resolves credentials for HTTP surfaces (chat URL `?token=` auth). It **prefers SharedGatewayToken** over DeviceToken because HTTP endpoints expect the shared token, not the per-device WebSocket token. ## Client instance lifecycle @@ -168,9 +182,15 @@ Setup codes (from QR scan or paste) decode to `{ url, bootstrapToken }` via `Set **Approval boundaries**: `GatewayConnectionManager` leaves node-pair command-trust requests and reapproval pending for explicit operator approval. It may automatically approve and reconnect only an explicitly typed device-pair request used for a device role upgrade. +## Inbound pairing approval (operator) + +When **another** device or node requests pairing, the gateway broadcasts `device.pair.requested` / `node.pair.requested` to operators with pairing scope. `OpenClawGatewayClient` refreshes the pending lists and raises `DevicePairListUpdated` / `NodePairListUpdated`, which `GatewayService` forwards via its `PairListsChanged` event. + +`PairingApprovalCoordinator` (tray) reconciles those snapshots through the pure `PairingApprovalQueue` (OpenClaw.Connection) into add/resolve deltas, de-duplicating, suppressing already-decided requests, and filtering out the local node's own pending request (handled by the auto-approve path above). For genuinely new requests — when `ShowPairingApprovalDialog` is enabled and the operator holds pairing scope — it raises `ApprovalRequested`, and the app presents a focused **`PairingApprovalDialog`** plus an awareness toast (with a "Review" action). The dialog shows the requester's identity and the **operator scopes being granted** (mapped to friendly text by `PairingScopeDescriptions`), with Approve / Reject / Decide-later. Approve is briefly disabled on each new request to prevent click-through. Approve/Reject call the `IOperatorGatewayClient.{Device,Node}Pair{Approve,Reject}Async` RPCs; the queue advances and the dialog closes when empty. The existing Connections-page "Pending approvals" banner remains as the passive fallback when the dialog is disabled. Pure queue/scope logic is unit-tested in `OpenClaw.Connection.Tests`. + ## SSH tunnel integration -`SshTunnelService` manages an SSH local port-forward process. `SshTunnelManager` wraps it behind `ISshTunnelManager` for the connection manager. +`SshTunnelService` manages an SSH local port-forward process and implements `ISshTunnelManager` directly for the connection manager. When a `GatewayRecord` has `SshTunnel` config, the connection manager starts the tunnel before connecting the WebSocket client to `ws://localhost:`. The config stores the SSH daemon port (`sshPort`, default `22`) separately from the remote gateway port forwarded by `-L`. @@ -194,8 +214,9 @@ The `EnableMcpServer=true`, `EnableNodeMode=false` path creates a local-only `No Tray actions should never silently no-op on common pairing/configuration issues: - Chat resolves credentials from the active registry record and per-gateway identity. If no usable credential exists, it opens Connection settings instead. -- Canvas opens only when the Windows node is initialized and paired; otherwise it opens Connection settings. +- Canvas opens only when the Windows node is initialized, paired, and the Canvas capability is enabled in settings; otherwise it opens Connection settings. - Quick Send uses the live operator client and surfaces scope/pairing errors from gateway calls. +- `system.run` and `system.run.prepare` are gated by `NodeSystemRunEnabled` (default `true` for backward compatibility). When disabled, those commands are dropped from advertised capabilities and invocations are rejected. ## Legacy migration diff --git a/docs/CONNECTION_PROTOCOL_RESEARCH.md b/docs/CONNECTION_PROTOCOL_RESEARCH.md index d072f90fd..e35151058 100644 --- a/docs/CONNECTION_PROTOCOL_RESEARCH.md +++ b/docs/CONNECTION_PROTOCOL_RESEARCH.md @@ -47,7 +47,7 @@ Public upstream gateway sources reviewed: - `https://github.com/openclaw/openclaw/blob/main/src/gateway/server-methods/nodes.ts` - `https://github.com/openclaw/openclaw/blob/main/packages/gateway-protocol/src/schema/frames.ts` -The setup engine currently pins gateway LKG `2026.6.1` in +The setup engine currently pins gateway LKG `2026.6.11` in `src/OpenClaw.SetupEngine/GatewayLkgVersion.cs`. Before implementing behavior that depends on newer upstream `main`, compare the installed LKG against the reviewed upstream docs/code. diff --git a/docs/DATA_FLOW_ARCHITECTURE.md b/docs/DATA_FLOW_ARCHITECTURE.md index 42cedf07e..d33643a70 100644 --- a/docs/DATA_FLOW_ARCHITECTURE.md +++ b/docs/DATA_FLOW_ARCHITECTURE.md @@ -47,7 +47,7 @@ src/OpenClaw.Tray.WinUI/Services/AppState.cs ### GatewayService (`Services/GatewayService.cs`) -Owns all 27 operator gateway client event subscriptions. Moved from App.xaml.cs to separate concerns. +Owns the operator gateway client event subscriptions, including data events and connection lifecycle events. Moved from App.xaml.cs to separate concerns. ``` src/OpenClaw.Tray.WinUI/Services/GatewayService.cs diff --git a/docs/MCP_MODE.md b/docs/MCP_MODE.md index 9868d2acf..0065dd2d3 100644 --- a/docs/MCP_MODE.md +++ b/docs/MCP_MODE.md @@ -4,7 +4,7 @@ ## Summary -The Windows tray app now ships a **local Model Context Protocol (MCP) server** alongside its existing OpenClaw gateway client. The same node capabilities the agent reaches over the OpenClaw gateway WebSocket — `system.run`, `screen.snapshot`, `canvas.*`, `camera.list`, `camera.snap`, `camera.clip`, `location.get`, `tts.speak`, `system.notify`, `system.execApprovals.*` — are advertised, on the same machine, as MCP tools over `http://127.0.0.1:8765/`. +The Windows tray app now ships a **local Model Context Protocol (MCP) server** alongside its existing OpenClaw gateway client. The same node capabilities the agent reaches over the OpenClaw gateway WebSocket — `system.*`, `screen.*`, `canvas.*`, `camera.*`, `location.get`, `tts.*`, `stt.*`, `device.*`, and `browser.proxy` — are advertised, on the same machine, as MCP tools over `http://127.0.0.1:8765/`. Local-only `app.*` and `app.connection.*` tools are also exposed to MCP clients for tray automation and connection/pairing workflows; those are not registered with the remote gateway node transport. This means any local MCP client (Claude Desktop, Claude Code, Cursor, an MCP-aware CLI, a custom dev script) can reach into the running tray and drive Windows-native capabilities directly, without an OpenClaw gateway in the loop. The tray app can run in **MCP-only mode** with no gateway connection at all. @@ -100,17 +100,19 @@ public bool EnableNodeMode { get; set; } // open WebSocket to gateway public bool EnableMcpServer { get; set; } // run local MCP HTTP server ``` -| `EnableNodeMode` | `EnableMcpServer` | Result | +| `EnableNodeMode` | `EnableMcpServer` | Behavior | |---|---|---| -| off | off | Operator-only (legacy default) | -| off | on | **MCP server only, no gateway** | -| on | off | Gateway node, no MCP | -| on | on | Gateway node + MCP | +| false | false | Operator-only (legacy default) | +| false | true | **MCP server only, no gateway** | +| true | false | Gateway node, no MCP | +| true | true | Gateway node + MCP | Settings UI exposes both toggles in the Advanced section, with the live MCP endpoint URL and current status (`Listening` / `Stopped — save and restart to start` / `Disabled`). A legacy `McpOnlyMode` field is migrated automatically on load and never re-written. +MCP startup is reported from the actual listener state. `NodeService.McpStartupError` is populated when capability registration or the HTTP listener fails, and MCP-only startup is not treated as successful unless the loopback MCP server is running. Tray, Permissions, and Command Center surfaces show local MCP-only separately from gateway connectivity so a working local MCP listener is never presented as a gateway connection. + ## Why this matters ### Testing @@ -151,6 +153,34 @@ The exact same node tools the OpenClaw gateway uses are now invocable by any loc In all cases the user gets a Windows-native agent experience without OpenClaw infrastructure. They can be entirely offline w.r.t. an OpenClaw gateway and still hand the LLM a working set of "do something on my Windows box" tools. +### Current command surface + +The canonical command descriptions live in `OpenClaw.Shared\Mcp\McpToolBridge.CommandDescriptions`; `OpenClaw.WinNode.Cli.Tests\SkillMdDriftTests` keeps `src\OpenClaw.WinNode.Cli\skill.md` in sync with that documented capability surface. The live `tools/list` output may also include newly registered capabilities with fallback descriptions before prose is updated. + +Gateway/node command groups currently include: + +- `system.notify`, `system.run`, `system.run.prepare`, `system.which`, `system.execApprovals.get`, `system.execApprovals.set` +- `canvas.present`, `canvas.hide`, `canvas.navigate`, `canvas.eval`, `canvas.snapshot`, `canvas.a2ui.push`, `canvas.a2ui.reset`, `canvas.a2ui.dump`, `canvas.caps`, `canvas.a2ui.pushJSONL` +- `screen.snapshot`, `screen.record` +- `camera.list`, `camera.snap`, `camera.clip` +- `stt.transcribe`, `stt.listen`, `stt.status` +- `tts.speak`, `tts.status` +- `location.get` +- `device.info`, `device.status` +- `browser.proxy` + +Local MCP-only app control commands currently include: + +- `app.navigate`, `app.status`, `app.sessions`, `app.agents`, `app.nodes`, `app.config.get`, `app.settings.get`, `app.settings.set`, `app.menu`, `app.search`, `app.dashboard.url` +- Chat automation: `app.chat.snapshot`, `app.chat.send`, `app.chat.reset` +- Connection automation: `app.connection.applySetupCode`, `app.connection.connectSharedToken`, `app.connection.pendingApprovals`, `app.connection.approveDevicePairing`, `app.connection.rejectDevicePairing`, `app.connection.approveNodePairing`, `app.connection.rejectNodePairing`, `app.connection.reconnect`, `app.connection.reconnectNode` + +Example chat automation smoke: + +```powershell +winnode --command app.chat.send --params '{"message":"hello from local MCP"}' +``` + ### Dev acceleration when building new features This is the strongest argument for making MCP a first-class citizen, not an afterthought. @@ -271,6 +301,22 @@ curl -s -X POST http://127.0.0.1:8765/ ` For a simpler local CLI smoke test, run `winnode --list-tools`; it loads the same token file automatically. +For agent-driven validation, use the repo-local skill +`.agents/skills/openclaw-proof-validation/SKILL.md`. MCP/node changes need live +tool discovery plus invocation proof using `winnode` or raw MCP JSON-RPC. + +## Adding or changing node commands + +Every new Windows node command must remain first-class over local MCP. Register +it in the capability path used by `NodeService`, update +`McpToolBridge.CommandDescriptions`, update +`src/OpenClaw.WinNode.Cli/skill.md`, and add focused tests. `SkillMdDriftTests` +guards against drift between capabilities, MCP descriptions, and `winnode` docs. + +PR proof for a new command should paste `winnode --list-tools` plus the command +invocation, or raw MCP `tools/list` plus `tools/call`; include gateway invoke +output when gateway-mediated behavior changed and a gateway is available. + For Claude Code, drop this into `.mcp.json` at the repo root or `~/.claude.json`: ```json diff --git a/docs/MISSION_CONTROL.md b/docs/MISSION_CONTROL.md index 3c1394ed8..d3629853d 100644 --- a/docs/MISSION_CONTROL.md +++ b/docs/MISSION_CONTROL.md @@ -22,7 +22,7 @@ The main product decision is deliberate: **do not make a native Windows gateway Windows now has a strong foundation: -- Node Mode with canvas, camera, screen snapshot/record, location, device info/status, system commands, notifications, and exec approval policy. +- Node Mode with canvas, camera, screen snapshot/record, location, device info/status, system commands, notifications, exec approval policy, and local MCP `app.chat.*` automation commands. - Command Center status detail window with channels, sessions, usage, local/operator node inventory, allowlist diagnostics, pairing warnings, and activity stream. - SSH tunnel settings and service. - Activity Stream and support-bundle copy path that avoid storing invoke payloads. @@ -465,6 +465,15 @@ Deliverables: - Hover HUD / richer tray tooltip: **implemented with topology, channel, node, warning, and activity summary** - Update status: **implemented in Command Center support/debug section and copied support context, including current version, latest prompted version when known, and last check outcome** +Recent native chat behavior implemented during this phase: + +- Queued-message UI tracks local send state (`Queued`, `Sending`, `Failed`) until the gateway confirms or rejects the turn. +- Timeline virtualization keeps long chat histories responsive while preserving stable render identity for visible entries. +- Completed sessions are hidden by default in the native chat session list, with active/in-progress sessions surfaced first. +- TTS notification speech preserves full assistant text while UI preview truncation remains visual-only. +- Slash-command suggestions use the gateway command catalog grouped into Mac-compatible command buckets. +- Local MCP chat automation exposes `app.chat.snapshot`, `app.chat.send`, and `app.chat.reset` for current-thread inspection, send, and reset flows. + Risk: medium; mostly UI and gateway method plumbing. ### Phase 8: Optional local Windows gateway convenience diff --git a/docs/ONBOARDING_V2.md b/docs/ONBOARDING_V2.md deleted file mode 100644 index abfbeb07b..000000000 --- a/docs/ONBOARDING_V2.md +++ /dev/null @@ -1,162 +0,0 @@ -# OpenClaw Setup — V2 (redesigned onboarding flow) - -Status: **the only setup UI shell in the app**. Setup is now scoped to -installing a new app-owned local WSL gateway. Existing and remote gateway -management lives in the tray app's Connections tab. - -## Where the V2 code lives - -| Project / file | Role | -| --- | --- | -| `src/OpenClawTray.OnboardingV2/` | New class library: state, app shell, page components, animations, V2Strings. Builds against `OpenClawTray.FunctionalUI` (the "minimal Reactor"). | -| `src/OpenClawTray.OnboardingV2/Pages/` | One file per page: `WelcomePage.cs`, `LocalSetupProgressPage.cs`, `GatewayWelcomePage.cs`, `PermissionsPage.cs`, `AllSetPage.cs`. | -| `src/OpenClawTray.OnboardingV2/Animations.cs` | Composition-animation helpers (`WithEntranceFadeIn`, `WithEntrancePopIn`, `WithSlideInFromBelow`, `WithBreathe`). All gated on `ShouldAnimate` (false in capture mode and when `UISettings.AnimationsEnabled == false`). | -| `src/OpenClawTray.OnboardingV2/V2Strings.cs` | Resource-key dictionary + settable `Resolver` delegate. `Get(key)` falls back to the bundled English values when the resolver returns null/empty/echoes the key. | -| `src/OpenClawTray.OnboardingV2/OnboardingV2State.cs` | Mutable shared state with property setters that raise `StateChanged` (the V2 app subscribes and bumps a render tick). Includes cutover-staged shape: `GatewayUrl`, `GatewayHealthy`, `LaunchAtStartup`, `Permissions` (`IReadOnlyList?`), `PermissionRowSnapshot`, `PermissionSeverity`. | -| `src/OpenClawTray.OnboardingV2/OnboardingV2App.cs` | Root `Component`. Owns the page area + nav bar (Back / Next-or-Finish + dot indicator). Welcome has no chrome by design. | -| `src/OpenClaw.SetupPreview/` | Standalone WinUI 3 unpackaged exe used for the inner-loop. Mounts the V2 tree against a fake `OnboardingV2State`. Reads env vars to switch page / scenario / locale and to enter capture mode (`OPENCLAW_PREVIEW_CAPTURE=1`). | -| `tools/v2_visual_diff.py` | Renders side-by-side `expected | actual` PNGs by spawning the SetupPreview exe in capture mode for each page scenario. The agent then *views* those PNGs and judges visual parity. | -| `tools/v2-design-refs/Dialog{,-1..-6}.png` | Designer source of truth (committed). | - -## How the inner loop works - -``` -edit V2 page → python tools/v2_visual_diff.py --pages welcome - → view out/v2-visual/welcome/diff.png - → iterate -``` - -`v2_visual_diff.py` does an incremental `dotnet build` of -`OpenClaw.SetupPreview` once per invocation (cached so `--all` only -builds once). Each page render takes ~2-3 s on a warm tree. - -Page scenarios baked into `PAGES` in `tools/v2_visual_diff.py`: - -| Key | Page | Notes | -| --- | --- | --- | -| `welcome` | Welcome | `Dialog.png` — no chrome, lobster + CTA + Advanced setup. | -| `progress-running` | LocalSetupProgress (in-flight) | `Dialog-1.png` — running stage card. | -| `progress-failed` | LocalSetupProgress (failure) | `Dialog-6.png` — pink Try-again card slides in. | -| `gateway` | GatewayWelcome | `Dialog-2.png` — gateway URL + health checkmark. | -| `permissions` | Permissions | `Dialog-5.png` — 5 capability rows + Refresh status. | -| `allset` | AllSet (node-mode active) | `Dialog-4.png` — amber Node-Mode card + Launch toggle. | -| `allset-no-node` | AllSet (node-mode off) | Variant — no amber card. | - -## Cutover - -The V2 flow is mounted in the live app via `OnboardingWindow`. The old -standalone/fallback v1 setup shell and pages have been removed. The -provider/model setup experience is hosted by the explicit tray-side -`GatewayWizardPage` / `GatewayWizardState` pair and embedded inside V2's -`GatewayWelcomePage`. - -Service wiring is centralised in -[`OnboardingV2Bridge`](../src/OpenClaw.Tray.WinUI/Onboarding/V2/OnboardingV2Bridge.cs): - -| Real service | V2 state field | Notes | -| --- | --- | --- | -| `LocalGatewaySetupEngine.StateChanged` | `LocalSetupRows`, `LocalSetupErrorMessage` | Re-uses `LocalSetupProgressStageMap` so setup stage behavior stays consistent. | -| `PermissionChecker.CheckAllAsync` + `SubscribeToAccessChanges` | `Permissions` | Snapshot list of `PermissionRowSnapshot`. Marshals back to UI thread. | -| `SettingsManager.GetEffectiveGatewayUrl` | `GatewayUrl` | Flips `ws://` → `http://` for the browser-launch link. | -| `SettingsManager.AutoStart` ↔ `LaunchAtStartup` | `LaunchAtStartup` | Two-way: initial value from settings; toggle change calls `_settings.Save()`. | -| `Settings.EnableNodeMode` | `NodeModeActive` | Seeded once at construction. | -| `GatewayRegistry` + WSL distro probe | `ExistingGateway` | Drives Welcome CTA/warning behavior for none, app-owned local WSL, and external-only connections. | - -Threading: every cross-thread mutation marshals through -`DispatcherQueue.TryEnqueue`. The V2 state's `StateChanged` event fires -on the UI thread, bumping a render tick in -[`OnboardingV2App.UseEffect`](../src/OpenClawTray.OnboardingV2/OnboardingV2App.cs). - -Completion: `OnboardingWindow.TryCompleteOnboarding` treats -`V2Route.AllSet` as the terminal setup page. The bridge's `Finished` event -closes the window, which routes through the shared completion logic — -persisting `Settings.AutoStart` via `AutoStartManager`, firing -`OnboardingCompleted`, and launching `HubWindow` on the chat tab when -setup is complete. - -Advanced setup: Welcome's "Advanced setup" link raises -`OnboardingV2State.AdvancedSetupRequested`; `OnboardingWindow` closes setup -without completing it and opens `HubWindow` on the Connections tab. Users -connect to existing, remote, or manual gateways there. - -Existing connections: first-run setup no longer opens automatically when -there is any usable saved gateway connection. Users can intentionally start -local setup from the Connections tab via **Install new WSL Gateway**. - -Welcome CTA/warnings: - -1. No existing gateway: primary CTA stays **Set up locally**. -2. Existing app-owned WSL gateway: primary CTA becomes **Install new WSL Gateway**; confirmation warns that the current OpenClaw WSL gateway and `OpenClawGateway` distro will be deleted before a fresh install. -3. External-only gateway: primary CTA stays **Set up locally**; confirmation says a new local WSL gateway will be installed and connected, while the external gateway remains available in Connections. - -## Follow-up backlog - -The cutover deliberately scopes down to the items below to keep this PR -reviewable. None are blocking — V2 works end-to-end without them. - -1. **Restyle the gateway wizard to native V2 UI.** The current - `GatewayWizardPage` is no longer part of the v1 shell, but it still owns - its own card/buttons while the gateway-driven provider/model flow remains - embedded in V2. -2. **Real translations for V2_* keys.** `tools/seed_v2_resw.py` seeds - every V2_* key into all five `.resw` locales with the English value - and the `Resources_AreTranslatedAllOrNoneAcrossNonEnglishLocales` - test is taught (via a `key.StartsWith("V2_")` predicate) that they - are intentionally English-only at first ship. Translations land in - a follow-up by replacing each non-en-us value. - -## Animation discipline - -- All animations live in `src/OpenClawTray.OnboardingV2/Animations.cs`. - Pages opt in via extension methods (`element.WithEntranceFadeIn(...)`). -- Pages must call `ElementCompositionPreview.SetIsTranslationEnabled(fe, true)` - before animating `Translation`. The helper does this for you. -- The `ShouldAnimate` predicate gates every helper. It returns `false` - if `V2Animations.DisableForCapture` is set OR if - `Windows.UI.ViewManagement.UISettings.AnimationsEnabled` is `false` - (Windows reduce-motion). The SetupPreview sets `DisableForCapture` in - capture mode so screenshots are deterministic. -- Don't add page-local `Composition` calls; extend `Animations.cs` so - the gating stays centralised. - -## Accessibility checklist - -- [x] Re-enabled WinUI's system focus visuals (cyan ring) on every V2 - button by removing `UseSystemFocusVisuals = false`. -- [x] Stable `AutomationProperties.AutomationId` on Back / Next / - Finish nav buttons and on every page CTA. -- [x] `AutomationProperties.Name` on the AllSet launch-at-startup - `ToggleSwitch` (which uses empty `OnContent`/`OffContent` so the - "On" label can render to the toggle's left, matching the design). -- [x] `AutomationProperties.Name` on the custom title bar, the lobster - icon, and the title text. -- [ ] Keyboard nav verified end-to-end against the live UI (cutover - gate — capture mode skips animation, we should manually confirm - tab order in interactive mode). -- [ ] Screen reader smoke-test (Narrator + NVDA) at cutover. - -## Visual validation - -`python tools/v2_visual_diff.py --all` regenerates side-by-side -PNGs under `out/v2-visual//diff.png`. A human (or the agent -running this codebase) opens those PNGs and judges parity directly -against the designer references in `tools/v2-design-refs/`. We -intentionally do not pixel-diff — small, intentional rendering -differences (DPI scaling, font hinting, drop shadows) would dominate -the signal. - -When running visual validation: - -1. Render all pages: `python tools/v2_visual_diff.py --all`. -2. View each `diff.png` and note any discrepancies in: - - Layout / spacing / alignment - - Typography (size, weight) - - Color (especially accent cyan, accent green, error pink, amber - warning) - - Iconography (asset / size / position) - - Copy (the V2Strings dictionary holds the source of truth — the - designer mocks contain a couple of typos we intentionally fixed: - `localhost18789` → `http://localhost:18789`, `Stays` → `stays`, - and `Acvtive` → `Active`). -3. If any discrepancy matters, edit the relevant page, re-render, and - visually re-check until parity is restored. diff --git a/docs/ONBOARDING_WIZARD.md b/docs/ONBOARDING_WIZARD.md index d2e3944a6..26d6ba6d6 100644 --- a/docs/ONBOARDING_WIZARD.md +++ b/docs/ONBOARDING_WIZARD.md @@ -1,32 +1,41 @@ # Onboarding Wizard -The onboarding wizard is now the V2 setup flow for installing a new app-owned local WSL gateway on Windows. +The onboarding wizard installs a new app-owned local WSL gateway on Windows and then runs OpenClaw onboard. ## Overview On first launch, the wizard appears only when there is no usable saved gateway connection. Users with existing gateways manage connections from the tray app's Connections tab. The local WSL setup affordance in Connections is shown only when setup has not already created an app-owned WSL gateway on this device. -The V2 setup flow walks users through: +The setup flow walks users through: -1. **Welcome** — Greeting and introduction -2. **Local setup progress** — Fresh app-owned `OpenClawGateway` WSL installation -3. **Gateway setup** — Gateway-driven provider/model configuration hosted by `GatewayWizardPage` -4. **Permissions** — Windows system permission review -5. **All set** — Feature summary and completion +1. **Security notice** — Device-trust warning before setup choices +2. **Welcome / Advanced** — Install app-owned WSL gateway or connect existing gateway from Settings +3. **Capabilities** — Recommended profile, inline Windows permission status, and install review +4. **Local setup progress** — Fresh app-owned `OpenClawGateway` WSL installation +5. **Gateway installed** — Explicit handoff from infrastructure setup to OpenClaw onboard +6. **OpenClaw onboard** — Gateway-driven provider/model/key configuration +7. **All set** — Feature summary, startup preference, and completion -The setup flow no longer configures remote/manual gateways. The Welcome page's **Advanced setup** link closes setup and opens the tray app's Connections tab. +The setup flow no longer configures remote/manual gateways inline. The Welcome page's **Connect to an existing gateway** option routes through `AdvancedSetupPage`, closes setup, and opens the tray app's Connections tab. ## Screen Details ### Welcome -Displays the OpenClaw lobster icon, app title, and a brief description. If an app-owned local WSL gateway already exists, the primary CTA reads **Install new WSL Gateway** and confirmation warns that the current OpenClaw WSL gateway and distro will be deleted. If only an external gateway exists, the CTA remains **Set up locally** and confirmation explains that the external connection remains available in Connections. +Displays the OpenClaw icon, app title, and a brief description. If an app-owned local WSL gateway already exists, the primary CTA reads **Install new WSL Gateway** and confirmation warns that the current OpenClaw WSL gateway and distro will be deleted. If only an external gateway exists, the CTA remains **Set up locally** and confirmation explains that the external connection remains available in Connections. ### Local setup progress Installs and connects a new app-owned `OpenClawGateway` WSL instance from a clean WSL baseline. Setup does not export from or mutate an existing user Ubuntu distro; if WSL cannot create the named app-owned distro directly, setup fails with an actionable update message. When replacing an app-owned local gateway, the removal step is shown as part of progress and can be retried on failure. The managed distro is locked down and is not intended to be a normal interactive Ubuntu profile. For editing `openclaw.json` as the `openclaw` user and using root for protected-file administration, see [Managing the locked-down WSL gateway](WSL_GATEWAY_ADMIN.md). -### Wizard +### Capabilities and Windows permissions + +The Capabilities page applies the selected profile to both setup config and runtime `Node*` settings. Inline Windows permission rows are shown only for capabilities that need OS-level state (camera, microphone, location, screen capture). Notifications are always shown as an app-level permission. Screen capture is passive: Windows asks what to share each capture through the Graphics Capture picker. + +### OpenClaw onboard + +After OpenClaw onboard completes—or when the user explicitly skips it—local setup runs the pinned gateway CLI's non-interactive baseline initializer against the final runtime workspace, then writes fixed Windows-node guidance into a setup-owned managed section of that workspace's `AGENTS.md`. The section is replaced idempotently between markers, preserves user-authored `AGENTS.md` content and file permissions outside those markers, and does not modify OpenClaw source files. This helps the initial companion-app OpenClaw session know to use the Windows node / `nodes` tool for Windows desktop, files, screenshots, camera, notifications, browser proxy, and Windows command tasks. + Renders server-defined setup steps via RPC (`wizard.start` / `wizard.next`). The gateway controls the flow — steps can be: - **Note** — informational messages - **Confirm** — yes/no decisions @@ -38,18 +47,10 @@ If the gateway doesn't support the wizard protocol or is unreachable, this scree The wizard keeps recovery choices visible while setup steps are running so users can start the wizard again or skip it for now if an auth flow stalls. If the gateway restarts or the wizard connection is lost while setup is running, the same recovery choices are presented in the error state so the user is not trapped retrying a broken session. -### Permissions -Checks 5 Windows permissions using native APIs and registry: -- Notifications (Toast capability) -- Camera (Windows.Devices.Enumeration) -- Microphone (Windows.Devices.Enumeration) -- Screen Capture (Graphics.Capture) -- Location (optional, registry-based) - -Each permission shows its current status (Enabled/Disabled/Allowed/Denied) with an "Open Settings" button linking to the relevant `ms-settings:` URI. +When the gateway config wizard surfaces an error and the active gateway is an app-managed WSL distro, the error state also offers **Open terminal** and **Restart gateway**. The wizard does not parse or classify the gateway's error text; it leaves the message visible and selectable so the user can copy any command the gateway reports. The buttons reuse the shared `GatewayTerminalLauncher` and `WslGatewayController` (in `OpenClaw.Connection`, also used by the Connections tab). Restart re-enters the gateway config wizard (the provider/model onboarding step — not the whole V2 onboarding, and without re-installing the WSL distro) so fixes such as newly-installed tools are picked up on `PATH`. Because the gateway restart clears its wizard session, this resumes at the first config question rather than the exact step that failed. Detection is gated on `GatewayRecord.SetupManagedDistroName`, so it never appears for remote/SSH gateways. ### All set -Displays a completion summary, a Launch at startup toggle, and a Finish button that saves settings and closes setup. +Displays a completion summary, a Launch at startup toggle, and a Finish button that saves the startup preference before restarting the tray. Launch at startup defaults on so OpenClaw is ready after reboot. ## Security @@ -85,16 +86,15 @@ Use a temp settings directory for tests that construct `SettingsManager`, or set | Path | Purpose | |------|---------| -| `Onboarding/OnboardingWindow.cs` | Host window for the V2 setup shell | -| `src/OpenClawTray.OnboardingV2/OnboardingV2App.cs` | V2 Functional UI root component and page navigation | -| `src/OpenClawTray.OnboardingV2/OnboardingV2State.cs` | V2 shared setup state | -| `Onboarding/GatewayWizard/GatewayWizardState.cs` | Host-owned state for the embedded gateway wizard | -| `Onboarding/GatewayWizard/GatewayWizardPage.cs` | Embedded provider/model setup page inside V2 | -| `Services/LocalGatewaySetup/SetupCodeDecoder.cs` | Base64url setup code parsing used from Connections | -| `Onboarding/Services/InputValidator.cs` | Security input validation | -| `Onboarding/Services/WizardStepParser.cs` | Wizard JSON step parsing | -| `Onboarding/Services/LocalGatewayApprover.cs` | Local gateway URL classification | -| `Onboarding/Services/PermissionChecker.cs` | Windows permission checks | -| `Services/Connection/GatewayRegistry.cs` | Persistent gateway records and migration target | -| `Services/Connection/GatewayConnectionManager.cs` | Operator/node connection lifecycle used by onboarding | -| `Services/SetupExistingGatewayClassifier.cs` | Existing gateway classification for V2 Welcome and startup gating | +| `src/OpenClaw.SetupEngine.UI/SetupWindow.xaml(.cs)` | Tray-hosted setup shell, run lock, preview routing, and page navigation | +| `src/OpenClaw.SetupEngine.UI/Pages/SecurityNoticePage.xaml(.cs)` | First-run device-trust warning before setup choices | +| `src/OpenClaw.SetupEngine.UI/Pages/WelcomePage.xaml(.cs)` | Install-new-WSL vs connect-existing choice and existing-gateway replacement prompt | +| `src/OpenClaw.SetupEngine.UI/Pages/AdvancedSetupPage.xaml(.cs)` | Connect-existing handoff to Connection settings | +| `src/OpenClaw.SetupEngine.UI/Pages/CapabilitiesPage.xaml(.cs)` | Capability profile, inline Windows permission status, and install review | +| `src/OpenClaw.SetupEngine.UI/Pages/ProgressPage.xaml(.cs)` | WSL gateway install progress and gateway-installed handoff | +| `src/OpenClaw.SetupEngine.UI/Pages/WizardPage.xaml(.cs)` | OpenClaw onboard provider/model/key wizard driven by gateway `wizard.*` frames | +| `src/OpenClaw.SetupEngine.UI/Pages/CompletePage.xaml(.cs)` | Success, failure, log/help, and startup preference summary | +| `src/OpenClaw.SetupEngine.UI/Pages/SetupPermissionHelper.cs` | Passive Windows permission checks and inline permission rows | +| `src/OpenClaw.Connection/GatewayRegistry.cs` | Persistent gateway records and migration target | +| `src/OpenClaw.Connection/GatewayConnectionManager.cs` | Operator/node connection lifecycle used by onboarding | +| `src/OpenClaw.Tray.WinUI/Services/SetupExistingGatewayClassifier.cs` | Existing gateway classification for Welcome and startup gating | diff --git a/docs/OPERATOR_NODE_CONCEPTS.md b/docs/OPERATOR_NODE_CONCEPTS.md new file mode 100644 index 000000000..d317c9c09 --- /dev/null +++ b/docs/OPERATOR_NODE_CONCEPTS.md @@ -0,0 +1,82 @@ +# Operator and Node Concepts + +OpenClaw Companion connects a Windows PC to an OpenClaw gateway in two separate +roles. A new install can use both roles at once, but they have different jobs and +different approval paths. + +## Quick Glossary + +| Term | Meaning | +| --- | --- | +| Gateway | The OpenClaw service that coordinates agents, channels, sessions, devices, and nodes. The Windows app talks to it over WebSocket. | +| Local WSL gateway | A dedicated `OpenClawGateway` WSL distro installed by the Windows onboarding flow. It is app-owned and locked down rather than a general-purpose Ubuntu profile. | +| Operator | The user-facing control role. The tray app uses the operator connection for Quick Send, chat, diagnostics, channel controls, setup, and approving pairing requests. | +| Node | The controllable Windows machine role. When Node Mode is enabled, the tray app advertises Windows capabilities such as screenshots, canvas, camera, notifications, and approved command execution. | +| Pairing | The gateway approval flow that turns a new device or node request into a trusted identity with a stored device token. | +| Reapproval | A later approval request when a paired node asks for new or changed trust, such as command capability access. | +| Allowlisted node capability | A node command the gateway is explicitly allowed to invoke, configured in the gateway `allowCommands` list. Windows-side settings and policies can still block the command. | + +## How the Roles Work Together + +The operator role is the control surface. It signs in to the gateway, sends chat +messages, shows status, opens diagnostics, and approves device or node pairing +requests when the gateway says approval is required. + +The node role is the Windows capability surface. It tells the gateway which +Windows-native tools are available, then waits for approved gateway calls. Node +Mode does not mean every tool can run automatically. A capability has to be +enabled in Windows settings, allowed by the gateway, and in some cases approved +by a local Windows policy prompt. + +A typical local setup uses this sequence: + +1. OpenClaw Companion installs or connects to a gateway. +2. The tray app connects as an operator so you can send messages and manage setup. +3. If Node Mode is enabled, the same Windows app also connects as a node. +4. The gateway asks for pairing approval before trusting the new device or node. +5. After approval, the gateway can invoke only the node capabilities that are + enabled locally and allowlisted by gateway policy. + +## Local WSL Gateway Versus Existing Gateway + +The default onboarding path installs a local WSL gateway for users who do not +already have one. That gateway runs on the same Windows PC and is managed by the +OpenClaw Companion setup flow. + +Advanced setup is for users who already have a local, remote, or manually +managed gateway. In that case, the Windows app still uses the same operator and +node roles; only the gateway location and credentials are different. + +## Pairing, Tokens, and Reapproval + +Pairing is gateway-owned. Setup codes, bootstrap tokens, and shared gateway +tokens can help the app connect for the first time, but a paired device token +takes precedence after approval. This keeps long-lived operator and node +identity scoped to the gateway record that issued it. + +Some trust decisions are intentionally not automatic. Node command trust and +capability reapproval stay pending until an operator explicitly approves them, +so a new or changed node capability is visible before the gateway can use it. + +## Capability Allowlist + +Node Mode advertises available Windows commands, but the gateway decides which +commands it may call through `gateway.nodes.allowCommands` in +`~/.openclaw/openclaw.json`. Add exact command names such as `screen.snapshot`, +`canvas.present`, or `system.run`; wildcard entries are not expanded by the +gateway. + +Privacy-sensitive commands, especially `screen.record`, `camera.snap`, +`camera.clip`, `stt.transcribe`, `tts.speak`, and `system.run`, should only be +allowlisted when you want the gateway to be able to request that behavior. +Windows permissions, Node Mode toggles, and the local exec policy can still add +stricter checks. + +## Where to Go Next + +- Follow [Installation and setup](SETUP.md) for first-run onboarding and + troubleshooting. +- See [Node Mode](../README.md#-node-mode-agent-control) for capability names + and allowlist examples. +- Read [Connection architecture](CONNECTION_ARCHITECTURE.md) for contributor + details about token precedence, pairing, and connection lifecycle. diff --git a/docs/RELEASING.md b/docs/RELEASING.md index b24bc8a62..87f3b429f 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -161,12 +161,11 @@ For alpha tags, the **Build and Test** workflow should run: - `repo-hygiene` - `test` -- `e2etests` -- `build (win-x64)` -- `build (win-arm64)` +- `e2etests` shards: `setup-connect`, `revocation-recovery`, and `network-recovery` +- `build` matrix entries shown by GitHub as `build (win-x64)` and `build (win-arm64)` - `release` -MSIX jobs may appear as skipped while MSIX is paused. +The `setup-connect` E2E shard contains the MXC proof tests for the gateway -> Windows node -> `system.run` path and validates that the expected proof test names appear in the TRX output. GitHub-hosted runners may report those MXC proofs as skipped when the host is not MXC-capable; use `.\scripts\validate-mxc-e2e.ps1` for required local/self-hosted MXC merge validation. The `build-msix` job is disabled with `if: false` while MSIX is paused for alpha releases, so it should not appear in the required run list. The release job should: diff --git a/docs/SETUP.md b/docs/SETUP.md index f804f6501..5ed6d17ad 100644 --- a/docs/SETUP.md +++ b/docs/SETUP.md @@ -9,7 +9,9 @@ Before installing, make sure you have: - **Windows 10 (20H2 or later)** or **Windows 11** - **WebView2 Runtime** — pre-installed on Windows 11 and most up-to-date Windows 10 systems. If missing, download from [Microsoft Edge WebView2](https://developer.microsoft.com/microsoft-edge/webview2/). -You do **not** need a pre-existing local OpenClaw gateway before installing. On first launch, OpenClaw Companion can install a dedicated local WSL gateway for you, or you can use **Advanced setup** to connect to an existing local, remote, or manually configured gateway. +You do **not** need a pre-existing local OpenClaw gateway before installing. On first launch, OpenClaw Companion can install a dedicated local WSL gateway for you, or you can use **Advanced setup** to connect to an existing local, remote, or manually configured gateway. See [Onboarding Wizard](ONBOARDING_WIZARD.md) for the install-new-WSL and connect-existing handoff flow. + +New to the OpenClaw roles? Read [Operator and node concepts](OPERATOR_NODE_CONCEPTS.md) for a short glossary of gateway, local WSL gateway, operator, node, pairing, reapproval, and allowlisted node capabilities before starting setup. ## Step-by-Step Installation @@ -19,9 +21,9 @@ Download the latest stable installer from the canonical OpenClaw release assets: | File | Architecture | |------|-------------| -| [OpenClawCompanion-Setup-x64.exe](https://github.com/openclaw/openclaw/releases/latest/download/OpenClawCompanion-Setup-x64.exe) | Intel / AMD (most PCs) | -| [OpenClawCompanion-Setup-arm64.exe](https://github.com/openclaw/openclaw/releases/latest/download/OpenClawCompanion-Setup-arm64.exe) | ARM64 (Surface Pro X, Snapdragon laptops) | -| [OpenClawCompanion-SHA256SUMS.txt](https://github.com/openclaw/openclaw/releases/latest/download/OpenClawCompanion-SHA256SUMS.txt) | SHA-256 checksums | +| [OpenClawCompanion-Setup-x64.exe](https://github.com/openclaw/openclaw-windows-node/releases/latest/download/OpenClawCompanion-Setup-x64.exe) | Intel / AMD (most PCs) | +| [OpenClawCompanion-Setup-arm64.exe](https://github.com/openclaw/openclaw-windows-node/releases/latest/download/OpenClawCompanion-Setup-arm64.exe) | ARM64 (Surface Pro X, Snapdragon laptops) | +| [OpenClawCompanion-SHA256SUMS.txt](https://github.com/openclaw/openclaw-windows-node/releases/latest/download/OpenClawCompanion-SHA256SUMS.txt) | SHA-256 checksums | If you're unsure, use the **x64** installer. @@ -40,7 +42,7 @@ The installer offers optional shortcuts and startup integration: ### 4. First Launch -After the installer finishes, OpenClaw Companion starts automatically. Look for the 🦞 lobster icon in the system tray (bottom-right corner of the taskbar, near the clock). +After the installer finishes, OpenClaw Companion starts automatically. Look for the OpenClaw icon in the system tray (bottom-right corner of the taskbar, near the clock). If you don't see it, check the **hidden icons** area (the `^` arrow next to the tray). @@ -50,26 +52,21 @@ The installer also creates a Start Menu group with shortcuts for **OpenClaw Comp On first launch, Molty opens the onboarding wizard when there is no usable saved gateway connection. The default flow installs and configures a dedicated app-owned local WSL gateway: -1. **Welcome** — A friendly greeting introducing OpenClaw and Molty. Click **Install new WSL Gateway** to install a new local WSL gateway. +1. **Security notice** — Confirms this is a trusted PC before local setup starts. - If you already have a local or remote gateway, choose **Advanced setup** instead. This opens the tray app's Connections tab, where you can connect with an existing gateway URL, token, or setup code without installing a new local WSL gateway. +2. **Welcome** — Choose **Install a local gateway (WSL)** to install the app-owned WSL gateway, or **Connect to an existing gateway** to open the tray app's Connections tab. -2. **Capabilities** — Reviews the Windows node capabilities that can be enabled, such as system commands, canvas, screen capture, camera, location, browser automation, device controls, text-to-speech, and speech-to-text. + For the role split behind these choices, see [Operator and node concepts](OPERATOR_NODE_CONCEPTS.md). -3. **Local setup progress** — Installs a fresh app-owned `OpenClawGateway` WSL instance and connects Molty to it. This does not modify an existing user Ubuntu distro. +3. **Capabilities** — Choose a capability profile, review matching Windows permission status, and see exactly what setup will install before anything runs. -4. **Gateway setup** — If your gateway supports it, this screen walks you through gateway-driven configuration steps (AI provider selection, personality setup, communication channels). The steps are defined by your gateway via RPC. If the gateway doesn't support wizard mode, this screen is skipped automatically. +4. **Local setup progress** — Installs a fresh app-owned `OpenClawGateway` WSL instance and connects Molty to it. This does not modify an existing user Ubuntu distro. -5. **Permissions** — Reviews Windows system permissions needed for full functionality: - - **Notifications** — for toast alerts - - **Camera** — for camera capture - - **Microphone** — for voice input - - **Screen Capture** — for screenshots - - **Location** — optional, for location-aware features; packaged installs declare this capability so Windows may prompt for location consent the first time it is used +5. **Gateway installed** — Confirms the private gateway is running and offers **Start OpenClaw onboard**. - Each permission shows its current status. Click **Open Settings** next to any permission to jump directly to the relevant Windows Settings page. +6. **OpenClaw onboard** — Gateway-driven provider/model/key setup rendered as a transcript. Recovery options stay available if the gateway wizard needs attention. -6. **All set** — A summary of available features (tray menu, channels, voice, canvas, skills). Toggle **Launch at Login** to start Molty with Windows, then click **Finish** to complete setup. +7. **All set** — A summary of available features and startup preference. Fresh setup defaults launch-at-startup on; direct OpenClaw onboard preserves any existing startup preference. After the wizard, the tray icon turns green when connected. You can re-run the wizard or change settings anytime from the tray menu. @@ -188,7 +185,7 @@ Settings are stored at `%APPDATA%\OpenClawTray\settings.json`. If this file is c ## Updating -OpenClaw Companion checks for updates automatically and shows a notification when a new version is available. Click **Update** to download and apply the update. You can also manually check by re-downloading from the [OpenClaw Windows docs](https://docs.openclaw.ai/platforms/windows) or the [latest OpenClaw release](https://github.com/openclaw/openclaw/releases/latest). +OpenClaw Companion checks for updates automatically and shows a notification when a new version is available. Click **Update** to download and apply the update. You can also manually check by re-downloading from the [OpenClaw Windows docs](https://docs.openclaw.ai/platforms/windows) or the [latest OpenClaw Windows release](https://github.com/openclaw/openclaw-windows-node/releases/latest). ## Uninstalling diff --git a/docs/SETUP_ENGINE_REDESIGN.md b/docs/SETUP_ENGINE_REDESIGN.md index c8538e958..0fcc7111a 100644 --- a/docs/SETUP_ENGINE_REDESIGN.md +++ b/docs/SETUP_ENGINE_REDESIGN.md @@ -4,12 +4,14 @@ The Setup Engine is a **config-driven system** for provisioning an OpenClaw WSL gateway from scratch. It consists of two setup projects plus the tray host: -1. **`OpenClaw.SetupEngine`** — Headless pipeline library. Runs 18 steps sequentially with full JSONL logging, transaction journal, and rollback support. +1. **`OpenClaw.SetupEngine`** — Headless pipeline library. Runs 19 steps sequentially with full JSONL logging, transaction journal, and rollback support. 2. **`OpenClaw.SetupEngine.UI`** — WinUI3 setup window/pages that wrap the same pipeline with a fluent wizard UI. 3. **`OpenClaw.Tray.WinUI`** — The only shipped WinUI executable. It hosts `SetupWindow` directly and self-restarts after successful setup. The bundled `default-config.json` ships with the tray executable and provides secure defaults (loopback bind, WSL isolation, systemd enabled). Defaults can be overridden via config file or environment variables. +> **Status note (2026-07-06):** Current default setup includes `WindowsNodeBootstrapContextStep`, which injects Windows-node context into the WSL workspace `AGENTS.md` after onboarding. + --- ## Architecture @@ -18,7 +20,7 @@ The bundled `default-config.json` ships with the tray executable and provides se ┌─────────────────────────────────────────────────────────────┐ │ OpenClaw.SetupEngine (net10.0 library) │ │ │ -│ SetupPipeline ──→ 18 SetupStep classes ──→ StepResult │ +│ SetupPipeline ──→ 19 SetupStep classes ──→ StepResult │ │ │ │ │ │ SetupContext CommandRunner (WSL + Process) │ │ SetupConfig TransactionJournal (JSONL) │ @@ -31,7 +33,7 @@ The bundled `default-config.json` ships with the tray executable and provides se ┌─────────────────────────────────────────────────────────────┐ │ OpenClaw.SetupEngine.UI (net10.0-windows10.0.22621, WinUI3)│ │ SetupWindow + pages, direct code-behind, no MVVM │ -│ Welcome → Capabilities → Progress → Permissions → Complete │ +│ Security → Welcome → Capabilities → Progress → Onboard → Complete │ └─────────────────────────────────────────────────────────────┘ ▲ hosted by project reference │ @@ -63,11 +65,12 @@ src/OpenClaw.SetupEngine.UI/ ├── OpenClaw.SetupEngine.UI.csproj # WinAppSDK library referenced by tray ├── SetupWindow.xaml / .xaml.cs # 720×820 window, Mica, title bar, navigation, setup events └── Pages/ - ├── WelcomePage.xaml / .cs # Logo, info card, Install button + ContentDialog - ├── CapabilitiesPage.xaml / .cs # 2-column grid with icons + descriptions - ├── ProgressPage.xaml / .cs # Live step rows + streaming log viewer - ├── PermissionsPage.xaml / .cs # 5 permission checks + Open Settings buttons - └── CompletePage.xaml / .cs # Party popper, amber banner, startup toggle + ├── SecurityNoticePage.xaml / .cs # Device-trust warning + ├── WelcomePage.xaml / .cs # Install WSL gateway vs connect existing + ├── CapabilitiesPage.xaml / .cs # Profile, inline permissions, install review + ├── ProgressPage.xaml / .cs # Live step rows + gateway-installed handoff + ├── WizardPage.xaml / .cs # OpenClaw onboard transcript + └── CompletePage.xaml / .cs # Mascot status badge, summary, startup toggle ``` **Total engine code: ~1,882 lines across 8 files.** UI adds ~10 more files. @@ -163,7 +166,7 @@ src/OpenClaw.SetupEngine.UI/ --- -## Pipeline Steps (18 total) +## Pipeline Steps (19 total) Executed sequentially. Each step is a small class (30–120 lines) in `SetupSteps.cs`. @@ -186,7 +189,8 @@ Executed sequentially. Each step is a small class (30–120 lines) in `SetupStep | 15 | `PairNodeStep` | WebSocket node connection + capability registration | | 16 | `VerifyEndToEndStep` | End-to-end health check (operator → node round trip) | | 17 | `RunGatewayWizardStep` | Run/configure the gateway wizard unless skipped | -| 18 | `StartKeepaliveStep` | Background WSL keepalive to prevent VM shutdown | +| 18 | `WindowsNodeBootstrapContextStep` | Inject Windows-node context into the WSL workspace `AGENTS.md` | +| 19 | `StartKeepaliveStep` | Background WSL keepalive to prevent VM shutdown | ### Step Base Class @@ -252,7 +256,7 @@ Structured JSONL logger. Records sanitized entries for: - State transitions - Errors with stack traces -Log path defaults to `%APPDATA%\OpenClawTray\Logs\Setup\setup-.log` +Log path defaults to `%APPDATA%\OpenClawTray\Logs\Setup\setup-engine-.jsonl` for setup and `uninstall-engine-.jsonl` for uninstall. --- @@ -260,42 +264,42 @@ Log path defaults to `%APPDATA%\OpenClawTray\Logs\Setup\setup-.log` The WinUI app is a **thin shell** — no business logic, just rendering pipeline state. End-user UI runs default to `RollbackOnFailure=true`; `--no-rollback-on-failure` preserves an explicit debugging opt-out. -### Page Flow: Welcome → Capabilities → Progress → Permissions → Complete +### Page Flow: Security → Welcome → Capabilities → Progress → OpenClaw onboard → Complete + +**SecurityNoticePage** +- Native warning InfoBar for device-trust and setup transparency **WelcomePage** -- Lobster icon + "OpenClaw Setup" title bar -- Info card explaining what will be installed -- "Install new WSL Gateway" button with ContentDialog confirmation -- "Advanced setup" link → launches tray with `--page connection` +- OpenClaw icon + "OpenClaw Setup" title bar +- Install app-owned WSL gateway (recommended) or connect to existing gateway +- Replacement prompt when an app-owned WSL gateway already exists **CapabilitiesPage** -- 2-column grid showing capabilities from config -- Icons + descriptions for each (System, Canvas, Screen, Camera, etc.) -- "Continue" proceeds to Progress +- Capability profile defaults to Standard +- Inline Windows permission status for selected capabilities +- Install review showing WSL distro, OpenClaw CLI, local gateway service, and possible UAC **ProgressPage** - Step rows with spinning ProgressRing → ✓/✗ badges -- Live streaming log viewer (monospace, auto-scroll) -- On success → navigates to Permissions +- Live activity ledger collapsed by default +- On success → gateway-installed milestone with explicit OpenClaw onboard CTA - On failure → navigates to Complete(success=false) -**PermissionsPage** -- 5 permission rows: Notifications, Camera, Microphone, Location, Screen Capture -- Live status checks (registry, DeviceAccessInformation, GraphicsCaptureSession) -- "Open Settings" buttons launch `ms-settings://` URIs -- "Refresh status" button, "Continue" proceeds to Complete +**WizardPage** +- Transcript-style gateway `wizard.*` flow for provider/model/key setup +- Error state uses More options plus gateway recovery actions when available **CompletePage** -- Party popper image +- OpenClaw mascot with corner status badge - "All set!" / error heading -- Amber "Node Mode Active" warning banner -- "Launch OpenClaw at startup?" toggle (reported to tray host) -- "Finish" button asks the tray host to self-restart and open chat +- Native InfoBar for node mode +- "Launch OpenClaw at startup" toggle defaults on and is persisted before restart +- "Finish" asks the tray host to self-restart and open chat ### Window Properties - 720×820 logical pixels (DPI-scaled) - Mica backdrop -- Custom title bar with lobster icon +- Custom title bar with OpenClaw icon --- @@ -313,7 +317,9 @@ OpenClaw.SetupEngine.Program.Main(["--no-rollback-on-failure"]) OpenClaw.SetupEngine.Program.Main(["--log-path", "./trace.log"]) ``` -Exit codes: 0 = success, 1 = failure +Common flags include `--config`, `--headless`, `--dry-run`, `--rollback-on-failure`, `--no-rollback-on-failure`, `--log-path`, `--gateway-port`, and uninstall safety flags such as `--uninstall` plus `--confirm-destructive`. + +Exit codes: 0 = success, 1 = pipeline failure, 2 = bad arguments or setup lock/safety failure, 3 = cancelled ### UI (hosted by tray) diff --git a/docs/TEST_COVERAGE.md b/docs/TEST_COVERAGE.md index 67889f6cf..84b0c0cb0 100644 --- a/docs/TEST_COVERAGE.md +++ b/docs/TEST_COVERAGE.md @@ -1,6 +1,6 @@ # Test Coverage Summary -**Last audited**: 2026-05-22
+**Last audited**: 2026-07-06
**Framework**: xUnit / .NET 10.0
**Required validation status**: passing (`.\build.ps1`, Shared tests, Tray tests) @@ -11,27 +11,27 @@ These are the suites every agent must run after code changes, as documented in | Suite | Latest runtime result | |---|---:| -| `OpenClaw.Shared.Tests` | 1,920 total: 1,891 passed, 29 skipped | -| `OpenClaw.Tray.Tests` | 1,178 total: 1,178 passed, 0 skipped | +| `OpenClaw.Shared.Tests` | 2,734 total: 2,703 passed, 31 skipped | +| `OpenClaw.Tray.Tests` | 1,584 total: 1,584 passed, 0 skipped | -Runtime totals come from `dotnet test` on 2026-05-22. They are higher than +Runtime totals come from `dotnet test` on 2026-07-06. They are higher than method counts because some `[Theory]` tests expand into multiple cases. ## Test project inventory | Project | Primary scope | Test methods | |---|---|---:| -| `OpenClaw.Connection.Tests` | Gateway registry, credential resolution, connection manager/state machine, setup codes, pairing, diagnostics | 189 | -| `OpenClaw.Shared.Tests` | Shared models, gateway client, capabilities, MCP, exec approval, A2UI security, URL handling, notification categorization | 1,347 | -| `OpenClaw.Tray.Tests` | Tray state/UI helpers, settings isolation, onboarding, connection page behavior, localization, local gateway setup/uninstall | 786 | -| `OpenClaw.Tray.UITests` | Native WinUI/A2UI control and rendering coverage | 50 | -| `OpenClaw.WinNode.Cli.Tests` | Windows node CLI argument parsing, command behavior, JSON output, uninstall flow | 79 | -| `OpenClawTray.FunctionalUI.Tests` | Functional UI smoke coverage | 8 | -| `OpenClawTray.OnboardingV2.Tests` | Onboarding V2 page flow and state coverage | 9 | -| `OpenClaw.Tray.IntegrationTests` | Integration-test project scaffold; no `[Fact]`/`[Theory]` methods currently | 0 | - -The method inventory is a source scan of `[Fact]` and `[Theory]` attributes. Use -`dotnet test` for authoritative runtime totals. +| `OpenClaw.Connection.Tests` | Gateway registry, credential resolution, connection manager/state machine, setup codes, pairing, diagnostics | 325 | +| `OpenClaw.Shared.Tests` | Shared models, gateway client, capabilities, MCP, exec approval, A2UI security, URL handling, notification categorization | 1,977 | +| `OpenClaw.Tray.Tests` | Tray state/UI helpers, settings isolation, onboarding, connection page behavior, localization, local gateway setup/uninstall | 1,240 | +| `OpenClaw.Tray.UITests` | Native WinUI/A2UI control, rendering, and accessibility scan coverage | 64 | +| `OpenClaw.WinNode.Cli.Tests` | Windows node CLI argument parsing, command behavior, JSON output, uninstall flow | 89 | +| `OpenClaw.SetupEngine.Tests` | Setup engine, WSL gateway installation, setup-code, and local setup policy coverage | 284 | +| `OpenClawTray.FunctionalUI.Tests` | Functional UI smoke coverage | 10 | +| `OpenClaw.E2ETests` | Gateway-mediated setup/connect, revocation recovery, and network recovery suites | 21 | +| `OpenClaw.Tray.IntegrationTests` | Real-process tray/MCP integration tests gated by `OPENCLAW_RUN_INTEGRATION=1` | 18 | + +The method inventory is a source scan of `[Fact]`, `[Theory]`, and repo custom xUnit attributes such as `[E2EFact]`, `[MxcE2EFact]`, and `[IntegrationFact]`. Use `dotnet test` for authoritative runtime totals. ## Coverage highlights @@ -57,7 +57,26 @@ The method inventory is a source scan of `[Fact]` and `[Theory]` attributes. Use - **OpenClaw.Connection.Tests** keeps connection architecture tests separate from tray UI concerns. - **OpenClaw.Tray.UITests** covers A2UI/native WinUI rendering behavior that is awkward to validate through pure unit tests. - **OpenClaw.WinNode.Cli.Tests** covers the standalone Windows node CLI contract. -- **OpenClawTray.OnboardingV2.Tests** and **OpenClawTray.FunctionalUI.Tests** cover newer UI surfaces outside the main tray test project. +- **OpenClaw.SetupEngine.Tests** covers gateway setup and local WSL installation policy. +- **OpenClawTray.FunctionalUI.Tests** covers newer UI surfaces outside the main tray test project. +- **OpenClaw.E2ETests** uses custom `[E2EFact]` / `[MxcE2EFact]` attributes that inherit xUnit `FactAttribute`; CI exercises them with shard filters. +- **OpenClaw.Tray.IntegrationTests** uses custom `[IntegrationFact]` attributes and runs only when `OPENCLAW_RUN_INTEGRATION=1`. +- **PackagingTests** is a PowerShell-script lane under `tests\PackagingTests\`, not a dotnet test project. + +## Formal validation paths + +Use the smallest lane that proves the changed subsystem, but always include the +required closeout lane for code changes. + +| Lane | Entry point | Required when | +|---|---|---| +| Required closeout | `.\build.ps1`, Shared tests, Tray tests | Every code change and every agent closeout | +| GitHub-hosted PR/main CI | `.github\workflows\ci.yml` | Every pull request and push to `main`; runs normal E2E shards but skips MXC proofs on hosted runners | +| Accessibility scan | `dotnet test .\tests\OpenClaw.Tray.UITests\OpenClaw.Tray.UITests.csproj -r win-x64 --filter Category=Accessibility` | UI changes and CI quality gate; runs real-process Axe.Windows scans; see `docs\ACCESSIBILITY.md` | +| Local E2E | `OPENCLAW_RUN_E2E=1` with `OpenClaw.E2ETests` | Gateway setup/connect, recovery, or pairing changes that need real WSL Gateway coverage | +| Local MXC E2E | `.\scripts\validate-mxc-e2e.ps1` | MXC sandboxing, `system.run`, exec approvals, Windows node command execution, gateway setup/connect changes that affect MXC | +| Product WSL setup validation | `.\scripts\validate-wsl-gateway.ps1` | Tray onboarding/setup-engine changes that must prove the product WSL install path | +| Packaging script checks | `powershell -File .\tests\PackagingTests\Test-InnoUninstallOrdering.ps1` | Installer script changes that affect uninstall or cleanup ordering | ## Running tests @@ -76,6 +95,13 @@ dotnet test $env:OPENCLAW_RUN_E2E = "1" dotnet test .\tests\OpenClaw.E2ETests\OpenClaw.E2ETests.csproj -r win-x64 +# Formal MXC validation path. This sets the required integration/E2E env vars +# itself and fails when MXC proofs skip unless -AllowSkip is explicitly supplied. +.\scripts\validate-mxc-e2e.ps1 + +# Accessibility scan, matching the CI quality gate. +dotnet test .\tests\OpenClaw.Tray.UITests\OpenClaw.Tray.UITests.csproj -r win-x64 --filter Category=Accessibility + # Single project dotnet test .\tests\OpenClaw.Connection.Tests\OpenClaw.Connection.Tests.csproj @@ -97,3 +123,14 @@ first so `dotnet test --no-restore` cannot no-op before `bin\` exists. and memory usage over multi-day sessions. - Manual visual acceptance for complex WinUI surfaces where screenshot comparison would be brittle. + +For these gaps, affected changes must include the manual UI/MCP smoke described +in `AGENTS.md` and `.agents/skills/openclaw-proof-validation/SKILL.md`: launch +the tray from the current worktree, use computer-use / desktop automation for +visible WinUI paths, and validate local MCP with `winnode --list-tools` plus the +changed command when node capabilities are involved. + +When node command surfaces change, include +`OpenClaw.WinNode.Cli.Tests` in focused validation because `SkillMdDriftTests` +guards the capability registry, MCP descriptions, and `winnode` skill reference +from drifting apart. diff --git a/docs/VERSIONING.md b/docs/VERSIONING.md index 931261a18..3314672d1 100644 --- a/docs/VERSIONING.md +++ b/docs/VERSIONING.md @@ -15,6 +15,8 @@ imports GitVersion through `src\Directory.Build.props`, so normal `dotnet build` `.\build.ps1`, `.\run-app-local.ps1`, and CI builds all derive assembly metadata from the same tag history. +The repository-local tool manifest (`.config\dotnet-tools.json`) and MSBuild package reference (`src\Directory.Build.props`) are the authoritative local tool/package pins and currently target GitVersion 6.8.1. The CI workflow's `gittools/actions/gitversion/setup` step currently pins `6.4.x` for workflow output computation; if workflow files are being changed, prefer aligning that setup action to `6.8.x`. Until then, CI's tag/SemVer verification remains the release-blocking guard against version drift. + ## Tagged and untagged builds Tagged releases must resolve to the exact tag SemVer: diff --git a/docs/WINDOWS_NODE_TESTING.md b/docs/WINDOWS_NODE_TESTING.md index b408a803e..52cb4815b 100644 --- a/docs/WINDOWS_NODE_TESTING.md +++ b/docs/WINDOWS_NODE_TESTING.md @@ -12,8 +12,26 @@ The Windows Node feature allows the tray app to receive commands from the OpenCl 4. Toggle "Enable Node Mode" ON 5. Click Save +## Companion-App Setup Guidance + +For app-owned local WSL setup, after OpenClaw onboard completes or is explicitly skipped, setup runs the pinned gateway CLI's non-interactive baseline initializer against the final runtime workspace and then injects fixed Windows-node guidance into that workspace's `AGENTS.md`. The injected block is setup-owned and idempotently replaced between managed markers, preserving user-authored content and file permissions outside those markers and leaving OpenClaw source files unchanged. + +**Note on the apply script's WSL invocation.** The `WindowsNodeBootstrapContextStep` apply and rollback scripts are piped to `bash -s` via stdin (`RunInWslAsync(..., inputViaStdin: true)`) rather than the default `bash -c` argv path. This is required because `wsl.exe` performs shell variable expansion on argv before invoking bash, which would drop user-defined `$var` references in the multi-line script (`workspace='...'` followed by `mkdir -p "$workspace"` becomes `mkdir -p ""`). See `docs/WSL_EXE_ARGV_PITFALL.md` for the full writeup. + +The guidance helps the first companion-app OpenClaw session route Windows desktop, files, screenshots, camera, notifications, browser proxy, and Windows command tasks through the Windows node / `nodes` tool. + ## What You Can Test Now +### Agent-driven UI and MCP validation + +For changes touching tray UX, Settings, onboarding, chat/canvas, Command Center, Windows node capabilities, local MCP, gateway pairing/connection, permissions, or diagnostics, use `.agents/skills/openclaw-proof-validation/SKILL.md`. + +Short version: run required tests, collect a closeout proof pass with `.\run-app-local.ps1 -Isolated` when UI is involved, use computer-use or developer-provided screenshots/output for the active changed UI state, prove MCP with `winnode` or raw JSON-RPC, prove gateway paths when available, and include current-head concrete output under `## Real behavior proof`. Mid-development computer-use/MCP/rubber-duck validation is fine when explicitly requested or needed to unblock work. + +### New command MCP contract + +Every new Windows node call must be exposed through local MCP and `winnode`: register the capability, update `McpToolBridge.CommandDescriptions`, update `src/OpenClaw.WinNode.Cli/skill.md`, add focused tests, and prove discovery/invocation with `winnode` or raw MCP JSON-RPC. + ### 1. Settings Toggle - Verify the toggle appears in Settings under "ADVANCED" - Verify it saves and persists across app restarts @@ -59,7 +77,9 @@ These features need the gateway to send `node.invoke` commands: | `screen.snapshot` | Take screenshot | Captures screen, shows notification, returns base64 | | `screen.record` | Record short screen clip | Returns MP4/base64 metadata; requires explicit gateway allowlist | | `system.notify` | Show notification | Displays toast notification | -| `system.run` / `system.which` | Controlled command execution | Uses local exec approval policy; `prompt` decisions show a Windows Allow once / Always allow / Deny dialog | +| `system.run` | Controlled command execution | Uses local exec approval policy; `prompt` decisions show a Windows Allow once / Always allow / Deny dialog | +| `system.run.prepare` | Pre-flight command execution | Parses and validates a `system.run` invocation without executing it | +| `system.which` | Resolve executables | Returns absolute paths for requested binaries | | `camera.list` | Enumerate cameras | Returns device IDs and names | | `camera.snap` | Capture photo | Returns base64 image (NV12 fallback) | | `camera.clip` | Capture video clip | Returns MP4/base64 metadata | @@ -67,6 +87,9 @@ These features need the gateway to send `node.invoke` commands: | `device.info` / `device.status` | Device metadata/status | Returns host/app/locale plus battery/storage/network/uptime payloads | | `browser.proxy` | Proxy browser-control host requests | Requires Browser proxy bridge enabled, a compatible browser-control host listening on gateway port + 2, and matching browser-control auth | | `tts.speak` | Speak text aloud | Requires Text-to-speech playback enabled in Settings; gateway mode also requires `tts.speak` in `gateway.nodes.allowCommands` | +| `stt.transcribe` | Bounded microphone transcription | Requires Speech-to-text enabled in Settings; uses local Whisper.net | +| `stt.listen` | Voice-activity microphone transcription | Returns when the user stops speaking or timeout expires | +| `stt.status` | Speech-to-text readiness | Returns Whisper.net model download/readiness state | ## Capabilities Advertised @@ -79,6 +102,9 @@ When the node connects, it advertises these capabilities: - `device` - Host/app metadata and lightweight status - `browser` - Local `browser.proxy` bridge to a browser-control host on gateway port + 2, when enabled in Settings - `tts` - Windows speech synthesis or ElevenLabs playback, when enabled in Settings +- `stt` - Local speech-to-text via Whisper.net, when enabled in Settings + +Local MCP clients also see MCP-only `app.*` commands such as `app.navigate`, `app.status`, `app.chat.snapshot`/`app.chat.send`/`app.chat.reset`, and `app.chat.queue.list`/`app.chat.queue.cancel`. These are local testing and automation hooks registered with the tray's MCP server and are not advertised to the gateway WebSocket. ## Security Features @@ -122,35 +148,59 @@ When the node connects, it advertises these capabilities: ### Local sandbox validation - Sandbox integration tests are intended for local Windows development machines and may skip when the required local sandbox prerequisites are unavailable. - Build the tray app before running local sandbox validation so the required sandbox helper binaries are present in the app output. +- For MXC-related merge validation, prefer the formal script below because it sets the required gates and fails if MXC is skipped. + + ```powershell + .\scripts\validate-mxc-e2e.ps1 + ``` + +### Full Gateway `system.run` MXC runtime proof +- The focused E2E below provisions a fresh WSL Gateway, starts an isolated tray instance, sets a local exec approval rule through MCP, invokes `system.run` through the real Gateway `node.invoke` path, and verifies tray MXC diagnostics show contained `mxc-direct-appc` execution for both allowed execution and denied writes to the tray data directory. +- Run it when validating the Gateway/Windows node runtime path, not just direct MCP or shared library behavior. +- GitHub-hosted Actions runners do not provide a working MXC/AppContainer runtime. The regular cloud E2E matrix should report these MXC proofs as skipped while still running the rest of setup-connect. Run the proof on a local MXC-enabled Windows machine. Only set `OPENCLAW_RUN_MXC_E2E=1` in GitHub Actions when using an MXC-enabled self-hosted runner. +- Use `.\scripts\validate-mxc-e2e.ps1` for normal local validation. It sets `OPENCLAW_RUN_E2E` and `OPENCLAW_RUN_MXC_E2E`, runs the real Gateway MXC proofs, and fails if the MXC proof skips. `-AllowSkip` is only for documenting a non-MXC host, not for merge validation of MXC-related work. +- When reproducing this manually against an existing Gateway, make sure `gateway.nodes.allowCommands` includes `system.run`, `system.run.prepare`, and `system.which`, then approve any `pending-reapproval` request with `openclaw nodes approve `. The node can advertise `system.run` while the Gateway still blocks it until both gates are updated. ```powershell .\build.ps1 - $env:OPENCLAW_RUN_INTEGRATION='1' - dotnet test .\tests\OpenClaw.Shared.Tests\OpenClaw.Shared.Tests.csproj --filter "FullyQualifiedName~Mxc" + $env:OPENCLAW_REPO_ROOT = (Get-Location).Path + $env:OPENCLAW_RUN_E2E = "1" + dotnet test .\tests\OpenClaw.E2ETests\OpenClaw.E2ETests.csproj ` + --no-restore ` + --filter "FullyQualifiedName~RealGateway_SystemRun_ExecutesThroughWindowsNodeMxcSandbox" ` + --logger "console;verbosity=normal" ` + -r win-x64 ``` +- Expected proof markers: + - Gateway response contains `OPENCLAW_GATEWAY_SYSTEM_RUN_MXC_OK` with `exitCode=0`. + - The denied-write proof targets a fresh file under the isolated tray data directory, returns non-zero, and leaves that file absent. + - `openclaw-tray.log` contains `[mxc] system.run sandbox request` with `executor=mxc-direct-appc`, `contained=True`, and `shell=cmd`. + - `openclaw-tray.log` contains `[mxc] system.run sandbox result` with `containment=mxc` for both the successful execution and the denied write. +- E2E artifacts are written under `TestResults\E2E\` and skip known secret-bearing files such as gateway records and settings. + ## Remaining Work (Roadmap) 1. ~~**system.run + exec approvals**~~ ✅ Implemented - - `system.run` with PowerShell/cmd support - - `system.run.prepare` pre-flight command - - `system.which` command lookup - - `system.execApprovals` allowlist flow with base-hash optimistic concurrency for remote edits - - `system.run` environment override sanitizer blocks path/toolchain injection and secret-looking variables + - `system.run` with PowerShell/cmd support + - `system.run.prepare` pre-flight command + - `system.which` command lookup + - `system.execApprovals` allowlist flow with base-hash optimistic concurrency for remote edits + - `system.run` environment override sanitizer blocks path/toolchain injection and secret-looking variables 2. ~~**screen.record**~~ ✅ Implemented - - Graphics Capture video recording (MP4/base64) + - Graphics Capture video recording (MP4/base64) 3. ~~**camera.clip**~~ ✅ Implemented - - Short webcam video capture (MediaCapture + encoding) + - Short webcam video capture (MediaCapture + encoding) 4. ~~**A2UI pushJSONL alias + device status**~~ ✅ Implemented - - Legacy `canvas.a2ui.pushJSONL` - - Safe `device.info` / `device.status` + - Legacy `canvas.a2ui.pushJSONL` + - Safe `device.info` / `device.status` 5. ~~**Command Center diagnostics**~~ ✅ Implemented - - Channel/node/usage/pairing/allowlist diagnostics and recent invoke timeline + - Channel/node/usage/pairing/allowlist diagnostics and recent invoke timeline 6. **Packaging & consent prompts** - - MSIX packaging with camera/screen capabilities for system prompts + - MSIX packaging with camera/screen capabilities for system prompts 7. **Test matrix & polish** - - Canvas/screen/camera regression tests - - Handle timeouts/disconnects, reduce verbose logging + - Canvas/screen/camera regression tests + - Handle timeouts/disconnects, reduce verbose logging ## Files Involved diff --git a/docs/WSL_EXE_ARGV_PITFALL.md b/docs/WSL_EXE_ARGV_PITFALL.md new file mode 100644 index 000000000..aee6d6977 --- /dev/null +++ b/docs/WSL_EXE_ARGV_PITFALL.md @@ -0,0 +1,134 @@ +# WSL.exe argv variable-expansion pitfall + +## Summary + +`wsl.exe -- bash -c