diff --git a/docs/design/cli.md b/docs/design/cli.md index d2477d8a6370..51339fe18b92 100644 --- a/docs/design/cli.md +++ b/docs/design/cli.md @@ -1,18 +1,21 @@ --- -description: "Design document for the dotnet-maui CLI tool for AI-assisted development" +description: "Design document for the maui CLI tool" date: 2026-01-07 +updated: 2026-02-25 --- -# dotnet-maui CLI Design Document +# `maui` CLI Design Document ## Overview -The `dotnet-maui` CLI is a command-line tool that provides simple -commands for capturing screenshots, viewing logs, and inspecting the -visual tree of running .NET MAUI applications. While designed to -enable AI agents to iteratively develop and validate applications, -these commands are equally useful for developers who want quick access -to debugging and inspection capabilities from the terminal. +The `maui` CLI is a command-line tool for .NET MAUI development that provides two main capabilities: + +1. **Environment setup** — manages Android SDK/JDK, Xcode runtimes, simulators, and emulators +2. **App inspection** — captures screenshots, streams logs, and inspects the visual tree of running apps + +It is designed for three consumers: **AI agents**, **CI/CD pipelines**, and **humans**. + +**Full specification**: [PR #33865](https://github.com/dotnet/maui/pull/33865) — covers architecture, error contracts, IDE integration, JSON schemas, and vNext roadmap. ## Motivation @@ -24,51 +27,38 @@ simctl io booted screenshot`, while Android uses `adb exec-out screencap`. Similarly, log access, visual tree inspection, and device management all have platform-specific implementations. -The `dotnet-maui` CLI provides a unified interface across Android, +The `maui` CLI provides a unified interface across Android, iOS, macOS, Windows, and Mac Catalyst, making these operations simple and consistent for both developers and AI agents. +### Design Principles + +1. **Delegate to native toolchains** — wraps `sdkmanager`, `adb`, `xcrun simctl`, etc. +2. **Reuse shared libraries** — leverages [`dotnet/android-tools`](https://github.com/dotnet/android-tools) (`Xamarin.Android.Tools.AndroidSdk`) for SDK/JDK discovery, and contributes new capabilities (JDK installation, SDK bootstrap, license acceptance) back to it. +3. **Machine-first output** — every command supports `--json` +4. **Stateless** — each command reads state, acts, and exits +5. **Complement `dotnet run`** — uses the same device identifiers and framework options as [`dotnet run` for .NET MAUI][dotnet-run-spec] + ## Goals -1. **Screenshot capture**: Enable AI agents to capture screenshots of +1. **Environment setup**: Manage Android SDK/JDK, Xcode runtimes, + simulators, and emulators from a single tool + +2. **Screenshot capture**: Enable AI agents to capture screenshots of running .NET MAUI applications to validate visual changes -2. **Log access**: Provide unified access to platform-specific device +3. **Log access**: Provide unified access to platform-specific device logs (logcat, Console, etc.) -3. **Visual tree inspection**: Allow agents to inspect the runtime +4. **Visual tree inspection**: Allow agents to inspect the runtime visual tree structure and properties (.NET MAUI visual tree) -4. **Developer experience**: Integrate seamlessly with existing +5. **Developer experience**: Integrate seamlessly with existing `dotnet` CLI workflows, this should fit in with `dotnet run`, `dotnet watch`, etc. ## Installation and Invocation -The CLI will be available through multiple invocation methods to -support different workflows: - -### Method 1: Direct Tool Invocation - -```bash -dotnet-maui screenshot -o screenshot.png -``` - -### Method 2: .NET CLI - -```bash -dotnet maui screenshot -o screenshot.png -``` - -### Method 3: `dotnet tool exec` or `dnx` - -```bash -dotnet tool exec -y Microsoft.Maui.Cli screenshot -o screenshot.png -dnx -y Microsoft.Maui.Cli screenshot -o screenshot.png -``` - -### Installation - ```bash # As a global tool dotnet tool install --global Microsoft.Maui.Cli @@ -81,9 +71,10 @@ dotnet tool restore # Inline install and invocation dotnet tool exec -y Microsoft.Maui.Cli screenshot -o screenshot.png -dnx -y Microsoft.Maui.Cli screenshot -o screenshot.png ``` +The tool installs as `maui` on PATH. All commands in this document use the `maui` form. + The .NET workload specification includes support for automatically installing tools from workloads via the `tools-packs` feature (see [workload manifest specification][workload-spec]). However, this @@ -92,15 +83,126 @@ could be automatically installed when the `maui` workload is installed, eliminating the need for manual tool installation. Until then, manual installation via `dotnet tool install` will be how -we prove out the `dotnet-maui` CLI. +we prove out the `maui` CLI. [workload-spec]: https://github.com/dotnet/designs/blob/566ad4cafcc578d6389c215c61924ee9e07dcb29/accepted/2020/workloads/workload-manifest.md#tools-packs -## Command Structure +## Global Options -### Global Options +All commands support: -The `dotnet-maui` CLI follows the conventions established by [`dotnet +| Flag | Description | +|------|-------------| +| `--json` | Structured JSON output | +| `--verbose` | Detailed logging | +| `--interactive` | Control interactive prompts (default: `true` for terminals, `false` in CI or when output is redirected) | +| `--dry-run` | Preview actions without executing | +| `--platform

` | Filter by platform: `android`, `ios`, `maccatalyst`, `windows` | + +**Interactivity detection** follows the same pattern as `dotnet` CLI — auto-detects CI environments (`TF_BUILD`, `GITHUB_ACTIONS`, `CI`, etc.) and checks `Console.IsOutputRedirected`. + +## Environment Setup Commands + +### Android + +| Command | Description | +|---------|-------------| +| `maui android install` | Install JDK + SDK + recommended packages | +| `maui android install --accept-licenses` | Non-interactive install | +| `maui android install --packages ` | Install specific packages | +| `maui android jdk check` | Check JDK status | +| `maui android jdk install` | Install OpenJDK 21 | +| `maui android jdk list` | List installed JDKs | +| `maui android sdk list` | List installed packages | +| `maui android sdk list --available` | Show available packages | +| `maui android sdk install ` | Install package(s) | +| `maui android sdk accept-licenses` | Accept all licenses | +| `maui android sdk uninstall ` | Uninstall a package | +| `maui android emulator list` | List emulators | +| `maui android emulator create ` | Create emulator (auto-detects system image) | +| `maui android emulator start ` | Start emulator | +| `maui android emulator stop ` | Stop emulator | +| `maui android emulator delete ` | Delete emulator | + +Install paths and defaults are handled by [`dotnet/android-tools`](https://github.com/dotnet/android-tools). + +### Apple (macOS only) + +| Command | Description | +|---------|-------------| +| `maui apple install [--accept-license] [--runtime ]` | Optionally accepts Xcode license and installs simulator runtimes. Could prompt user to install Xcode in the future | +| `maui apple check` | Check Xcode, runtimes, and environment status | +| `maui apple xcode check` | Check Xcode installation and license | +| `maui apple xcode list` | List Xcode installations | +| `maui apple xcode select ` | Switch active Xcode | +| `maui apple xcode accept-license` | Accept Xcode license | +| `maui apple simulator list` | List simulators | +| `maui apple simulator create ` | Create simulator | +| `maui apple simulator start ` | Start simulator | +| `maui apple simulator stop ` | Stop simulator | +| `maui apple simulator delete ` | Delete simulator | +| `maui apple runtime check` | Check runtime status | +| `maui apple runtime list` | List installed runtimes | +| `maui apple runtime list --all` | List all runtimes (installed and downloadable) | +| `maui apple runtime install ` | Install an iOS runtime | + +> **License flag naming**: Android uses `accept-licenses` (plural) because `sdkmanager` requires accepting multiple SDK component licenses. Apple uses `accept-license` (singular) because `xcodebuild -license accept` accepts one unified Xcode license agreement. + +### Implementation References + +The `maui` CLI delegates to shared libraries for platform operations: + +**Android** — [`dotnet/android-tools`](https://github.com/dotnet/android-tools) (`Xamarin.Android.Tools.AndroidSdk`): + +| Feature | Implementation | +|---------|---------------| +| SDK discovery, bootstrap & license acceptance | [`SdkManager`](https://github.com/dotnet/android-tools/pull/275) | +| JDK discovery & installation | [`JdkInstaller`](https://github.com/dotnet/android-tools/pull/274) | +| ADB device management | [`AdbRunner`](https://github.com/dotnet/android-tools/pull/282) | +| AVD / Emulator management | [`AvdManagerRunner`](https://github.com/dotnet/android-tools/pull/283), [`EmulatorRunner`](https://github.com/dotnet/android-tools/pull/284) | + +**Apple** — wraps native toolchains directly: + +| Feature | Native tool | +|---------|------------| +| Simulator management | `xcrun simctl` (list, create, boot, shutdown, delete) | +| Runtime management | `xcrun simctl runtime` (list, add) | +| Xcode management | `xcode-select`, `xcodebuild -license` | +| Device detection | `xcrun devicectl list devices` (physical), `xcrun simctl list` (simulators) | + +Apple operations use [AppleDev.Tools][appledev-tools] for `simctl` and `devicectl` wrappers. + +### Device List + +The `maui` CLI also provides a unified device listing across all platforms: + +| Command | Description | +|---------|-------------| +| `maui device list` | List all connected devices, emulators, and simulators | +| `maui device list --platform android` | List Android devices and emulators only | +| `maui device list --platform ios` | List iOS simulators and devices only | +| `maui device list --json` | Machine-readable output for IDE/agent consumption | + +### Exit Codes + +All commands use consistent exit codes: + +| Code | Meaning | +|------|---------| +| 0 | Success | +| 1 | General error | +| 2 | Environment/configuration error | +| 3 | Permission denied (elevation required) | +| 4 | Network error (download failed) | +| 5 | Resource not found | + +## App Inspection Commands (Future) + +> **Note**: App inspection commands are planned for a future release. The initial release focuses on environment setup and device management. + +### Device Selection Options + +App inspection commands will follow the conventions established by [`dotnet run` for .NET MAUI][dotnet-run-spec], using the same device selection and framework options: @@ -146,7 +248,7 @@ Captures a screenshot of the currently running .NET MAUI application. **Usage:** ```bash -dotnet maui screenshot [options] +maui screenshot [options] ``` **Options:** @@ -158,17 +260,16 @@ dotnet maui screenshot [options] Initial implementation targets Android and iOS/Mac Catalyst, with Windows and macOS support planned as described below. -- **Android**: Uses `adb screencap` -- **iOS/Mac Catalyst**: Uses `simctl io screenshot` for simulator, and device capture via Xcode tooling (future implementation) +- **Android**: Uses `adb exec-out screencap -p` +- **iOS/Mac Catalyst**: Uses `xcrun simctl io booted screenshot ` for simulator; physical device capture via Xcode tooling (future) - **Windows** (planned): Uses Windows screen capture APIs to capture the active app window or full screen. - **macOS** (planned): Uses macOS screen capture APIs or command-line tooling to capture the active app window or full screen. ### Future Commands -To keep scope small for initial version, future commands are: - -- `dotnet maui log` or `logs` -- `dotnet maui tree` for displaying the visual tree +- `maui screenshot` for capturing screenshots of running apps +- `maui logs` for streaming device logs +- `maui tree` for inspecting the visual tree ## Integration with `dotnet run` and `dotnet watch` @@ -180,12 +281,10 @@ The CLI is designed to work seamlessly with existing .NET workflows: # Terminal 1: Run application with hot reload dotnet watch run -# Terminal 2: Monitor logs -dotnet maui logs --follow --filter "MyApp" - -# Terminal 3: Inspect application -dotnet maui screenshot --output iteration1.png -dotnet maui tree --format json +# Terminal 2: Inspect application +maui screenshot --output iteration1.png +maui logs --follow --filter "MyApp" # future +maui tree --json # future ``` ### AI Agent Workflow @@ -198,13 +297,13 @@ dotnet maui tree --format json sleep 2 # 3. Capture screenshot -dotnet maui screenshot -o current.png +maui screenshot -o current.png -# 4. Analyze visual tree -dotnet maui tree --format json +# 4. Analyze visual tree (future) +maui tree --json -# 5. Check logs for errors -dotnet maui logs --level error +# 5. Check logs for errors (future) +maui logs --level error # 6. Agent analyzes outputs and decides next steps ``` @@ -220,10 +319,10 @@ dotnet maui logs --level error ### iOS / Mac Catalyst - **Device Detection**: `xcrun simctl list devices` (simulators), - `xcrun devicectl list devices` (physical devices) + `xcrun devicectl list devices` (physical devices) — via [AppleDev.Tools][appledev-tools] - **Screenshots**: `xcrun simctl io booted screenshot ` - (simulators), iOS devices (future implementation) + (simulators), iOS physical devices (future) - **Logs**: `xcrun simctl spawn booted log stream` or Console.app (simulators), `mlaunch --logdev` (physical devices) @@ -243,6 +342,63 @@ The CLI is designed for development and debugging scenarios only: (like screenshots and logs), the CLI should not be usable against production applications +## IDE Integration + +The `maui` CLI is designed to be the shared backend for IDE extensions, eliminating duplicate environment detection and setup logic across tools. + +### Architecture + +IDEs spawn `maui` as a child process and consume its `--json` output: + +``` +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ +│ VS Code ext │ │ Visual Studio │ │ AI Agent │ +│ (vscode-maui) │ │ extension │ │ (Copilot, etc.) │ +└────────┬─────────┘ └────────┬──────────┘ └────────┬─────────┘ + │ │ │ + └───────────┬───────────┴────────────────────────┘ + │ + ┌──────▼──────┐ + │ maui CLI │ ← single tool, --json output + │ │ + │ ┌─────────┐ │ + │ │android- │ │ ← NuGet library (in-process) + │ │tools │ │ + │ └─────────┘ │ + └──────┬──────┘ + │ spawns native tools + ┌───────────┼───────────┐ + ▼ ▼ ▼ + ┌───────────┐ ┌──────────┐ ┌──────────┐ + │ adb │ │ xcrun │ │ Windows │ + │ sdkmanager│ │ simctl │ │ SDK │ + └───────────┘ └──────────┘ └──────────┘ +``` + +### How IDEs Use It + +| Workflow | CLI command | IDE behavior | +|----------|------------|--------------| +| Workspace open | `maui apple check --json`, `maui android jdk check --json` | Show environment status in status bar / problems panel | +| Environment fix | `maui android install --json` | Display progress bar, stream `type: "progress"` messages | +| Device picker | `maui device list --json` | Populate device dropdown / selection UI | +| Emulator launch | `maui android emulator start --json` | Show notification, update device list on completion | + +### Benefits of Reuse + +- **Consistent behavior** — VS Code, Visual Studio, and CLI all use the same detection and setup logic +- **Single maintenance point** — bug fixes and new features propagate to all consumers +- **AI-ready** — agents use the same `--json` output that IDEs consume +- **No protocol overhead** — simple process spawn + stdout, no daemon or RPC needed + +### Current Status + +| Integration | Status | +|-------------|--------| +| VS Code extension (`vscode-maui`) | ✅ In progress | +| Visual Studio extension | Planned (vNext) | +| GitHub Copilot / AI agents | ✅ Supported via `--json` output | + ## Future Goals ### MCP Server @@ -262,7 +418,8 @@ if there's demonstrated need. ### More Subcommands -There are other .NET MAUI CLI tools such as: +Environment setup commands (Android SDK/JDK, Xcode, emulators, +simulators) are now included above. These were inspired by: - .NET MAUI "Check" / "Doctor" - https://github.com/Redth/dotnet-maui-check @@ -270,15 +427,14 @@ There are other .NET MAUI CLI tools such as: - Android SDK Management - https://github.com/Redth/AndroidSdk.Tools -These could easily be added down the road. - -Future commands: +Future app inspection commands: -- `dotnet maui log` or `logs` for viewing console output -- `dotnet maui tree` for displaying the visual tree +- `maui logs` for viewing console output +- `maui tree` for displaying the visual tree +- `maui screenshot` for capturing screenshots -**Decision**: Start with just a few subcommands and expand in the -future. +**Decision**: Environment setup ships first. App inspection commands +follow in a future release. ## References diff --git a/docs/design/maui-devtools-ide-integration.md b/docs/design/maui-devtools-ide-integration.md new file mode 100644 index 000000000000..776009529d05 --- /dev/null +++ b/docs/design/maui-devtools-ide-integration.md @@ -0,0 +1,301 @@ +# MAUI Dev Tools — IDE Integration + +**Parent Document**: [MAUI Dev Tools Specification](./maui-devtools-spec.md) + +This document details how IDEs (Visual Studio, VS Code) integrate with MAUI Dev Tools. + +--- + +## Table of Contents + +1. [Extension Architecture](#1-extension-architecture) +2. [VS Code Integration](#2-vs-code-integration) +3. [Visual Studio Integration](#3-visual-studio-integration) +4. [Common UI Patterns](#4-common-ui-patterns) + +--- + +## 1. Extension Architecture + +### VS Code Extension + +``` +┌─────────────────────────────────────────────────────────────┐ +│ VS Code │ +├─────────────────────────────────────────────────────────────┤ +│ ┌──────────────────────────────────────────────────────┐ │ +│ │ MAUI Extension │ │ +│ ├──────────────────────────────────────────────────────┤ │ +│ │ • Environment Status Bar Item │ │ +│ │ • "MAUI: Setup Environment" command │ │ +│ │ • Problems panel integration │ │ +│ │ • Quick Fix code actions │ │ +│ └─────────────────────┬────────────────────────────────┘ │ +│ │ │ +│ │ CLI invocation (stdio) │ +│ ▼ │ +│ ┌──────────────────────────────────────────────────────┐ │ +│ │ MAUI Dev Tools Client │ │ +│ │ (spawned as child process) │ │ +│ └──────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────┘ +``` + +**Extension Responsibilities**: +1. Spawn `maui` process on activation +2. Send `maui doctor --json` request on workspace open +3. Display issues in Problems panel +4. Register "MAUI: Setup Environment" command +5. Show progress notifications during fixes + +### Visual Studio Extension + +- Integrates with Visual Studio's environment detection UI +- Surfaces issues in Error List window +- Provides menu items in Tools > MAUI submenu +- Can consume the Android/iOS provider packages directly (as a library) or invoke the `maui` CLI -- either way, the business logic is shared. This avoids duplicating environment detection and fix logic between VS and the CLI. + +--- + +## 2. VS Code Integration + +### Status Bar Item + +Always visible indicator of MAUI environment health: + +``` +$(check-circle) MAUI Ready ← Green when healthy +$(warning) MAUI: 2 issues ← Yellow with issue count +$(error) MAUI: Setup Required ← Red when critical +``` + +**Click Action**: Opens "MAUI Environment" panel + +### Environment Panel + +``` +┌────────────────────────────────────────────────────────────┐ +│ MAUI ENVIRONMENT [Refresh] │ +├────────────────────────────────────────────────────────────┤ +│ │ +│ .NET SDK │ +│ ├── ✓ .NET SDK 9.0.100 │ +│ └── ✓ MAUI Workload 9.0.0 │ +│ │ +│ Android │ +│ ├── ✓ Android SDK (/Users/dev/Android/sdk) │ +│ ├── ✓ Build Tools 34.0.0 │ +│ ├── ⚠ Emulator not running [Start] │ +│ └── ✓ Emulator: Pixel_5_API_34 │ +│ │ +│ iOS / macOS (Xcode 16.0) │ +│ ├── ✓ iOS 18.0 Runtime │ +│ ├── ✓ iPhone 16 Pro Simulator │ +│ └── ⚠ macOS 15.0 Runtime missing [Install] │ +│ │ +│ ─────────────────────────────────────────────────────────│ +│ [Fix All Issues] │ +└────────────────────────────────────────────────────────────┘ +``` + +**States**: +- ✓ Green checkmark: Component healthy +- ⚠ Yellow warning: Non-critical issue, fixable +- ✖ Red X: Critical issue, blocks development +- [Action]: Inline fix button + +### Fix Progress Dialog + +``` +┌────────────────────────────────────────────────────────────┐ +│ Setting up MAUI Environment │ +├────────────────────────────────────────────────────────────┤ +│ │ +│ ✓ Installing Android SDK │ +│ ✓ Installing build-tools;34.0.0 │ +│ ● Installing system-images;android-34;google_apis;x86_64 │ +│ ████████████░░░░░░░░░░░░░░░░░░░░░░ 45% (1.2 GB/2.6 GB)│ +│ ○ Creating Emulator Pixel_5_API_34 │ +│ ○ Verifying setup │ +│ │ +│ ─────────────────────────────────────────────────────────│ +│ [Cancel] ETA: 3 min │ +└────────────────────────────────────────────────────────────┘ +``` + +### Fix Failed Dialog + +When a fix operation fails: + +``` +┌────────────────────────────────────────────────────────────┐ +│ ✖ Fix Failed │ +├────────────────────────────────────────────────────────────┤ +│ │ +│ Unable to install Android SDK automatically. │ +│ │ +│ Error: Connection reset while downloading from │ +│ dl.google.com (E3004) │ +│ │ +│ Attempted: │ +│ • Retry download (3 times) │ +│ • Clear download cache │ +│ │ +│ This may be caused by: │ +│ • Corporate proxy/firewall blocking Google domains │ +│ • Network connectivity issues │ +│ • SSL inspection interfering with downloads │ +│ │ +│ ─────────────────────────────────────────────────────────│ +│ [Ask Copilot for Help] [View Logs] [Retry] [Cancel] │ +└────────────────────────────────────────────────────────────┘ +``` + +**"Ask Copilot for Help" Flow**: + +1. User clicks button or types `/maui-help` in Copilot Chat +2. Extension sends diagnostic context to Copilot +3. Copilot receives structured data + conversation prompt: + +``` +The MAUI Dev Tools detected an issue it couldn't fix automatically. + +**Issue**: Android SDK installation failed (E4001 - Connection reset) +**Environment**: macOS 15.0, corporate network with proxy +**Attempted**: 3 download retries, cache clear + +The diagnostic bundle is attached. Please help the user resolve this issue. +Common causes for this error include proxy configuration, firewall rules, +or SSL inspection. Ask clarifying questions if needed. +``` + +4. Copilot engages in conversational troubleshooting +5. Copilot can suggest manual steps or request tool actions with user approval + +--- + +## 3. Visual Studio Integration + +### Tools Menu + +``` +Tools +├── MAUI +│ ├── Check Environment... Ctrl+Shift+M, E +│ ├── Fix Environment Issues... Ctrl+Shift+M, F +│ ├── ───────────────────────── +│ ├── Android +│ │ ├── SDK Manager... +│ │ ├── Emulator Manager... +│ │ └── Device Log... +│ ├── iOS Simulators... +│ └── ───────────────────────── +│ └── Environment Report... +``` + +### Error List Integration + +Issues detected by `maui doctor` appear in Visual Studio's Error List window: + +| Severity | Code | Description | Project | +|----------|------|-------------|---------| +| ⚠️ Warning | MAUI001 | Android SDK build-tools outdated | Solution | +| ❌ Error | MAUI002 | iOS runtime 18.0 not installed | Solution | + +Double-clicking an item opens the fix dialog. + +### Output Window + +Detailed logs available in Output window under "MAUI Dev Tools" pane: + +``` +[15:32:01] Running environment check... +[15:32:02] ✓ .NET SDK 9.0.100 found +[15:32:02] ✓ MAUI workload installed +[15:32:03] ✗ Android SDK not found at expected locations +[15:32:03] Checked: ANDROID_HOME, ANDROID_SDK_ROOT, ~/Library/Android/sdk +[15:32:03] Environment check complete: 1 error, 0 warnings +``` + +--- + +## 4. Common UI Patterns + +### Interactive Prompting + +When running in interactive mode (terminal), the tool prompts for missing information: + +**Example: Emulator Creation with Missing Parameters**: +``` +$ maui android emulator create + +? Emulator name: My_Pixel_5 + +? Select device profile: + ❯ Pixel 5 (1080x2340, 440dpi) + Pixel 6 (1080x2400, 411dpi) + Pixel 7 Pro (1440x3120, 512dpi) + (more...) + +? Select system image: + ❯ android-34 | Google APIs | x86_64 (recommended) + android-34 | Google Play | x86_64 + android-33 | Google APIs | x86_64 + (more...) + +Creating emulator 'My_Pixel_5'... done +``` + +**Non-Interactive Mode**: +``` +$ maui android emulator create --non-interactive +Error: --name is required in non-interactive mode +``` + +**Example: Large Download Confirmation**: +``` +$ maui doctor --fix + +The following will be installed: + • system-images;android-34;google_apis;x86_64 (2.6 GB) + • iOS 18.0 Runtime (8.1 GB) + +Total download size: 10.7 GB + +? Proceed? [Y/n] +``` + +### Permission Prompt (AI Agent) + +When an AI agent requests a modification: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ AI Agent Request │ +│ "Install Android SDK build-tools" │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ The AI assistant wants to install: │ +│ • build-tools;34.0.0 (52 MB) │ +│ │ +│ This will modify your Android SDK installation. │ +│ │ +│ [Allow] [Allow Once] [Deny] │ +│ │ +│ □ Remember this choice for this session │ +└─────────────────────────────────────────────────────────────┘ +``` + +### Progress Notification + +For long-running operations, IDEs show progress: + +**VS Code**: Notification toast with progress bar +**Visual Studio**: Status bar progress indicator + Output window details + +Progress updates include: +- Current operation name +- Percentage complete (when determinable) +- Bytes downloaded / total (for downloads) +- ETA (estimated time remaining) +- Cancel button diff --git a/docs/design/maui-devtools-spec.md b/docs/design/maui-devtools-spec.md new file mode 100644 index 000000000000..addaaca4bcf6 --- /dev/null +++ b/docs/design/maui-devtools-spec.md @@ -0,0 +1,1450 @@ +# MAUI Dev Tools Client — Product Specification + +**Version**: 2.16-draft +**Status**: Proposal +**Last Updated**: 2026-02-26 + +--- + +## Table of Contents + +1. [Executive Summary](#1-executive-summary) +2. [Problem Statement](#2-problem-statement) +3. [Goals, Non-Goals & Personas](#3-goals-non-goals--personas) +4. [Functional Requirements](#4-functional-requirements) +5. [Non-Functional Requirements](#5-non-functional-requirements) +6. [Architecture](#6-architecture) +7. [Public API Surface](#7-public-api-surface) +8. [User Experience](#8-user-experience) +9. [Diagnostics](#9-diagnostics) +10. [MVP vs vNext Features](#10-mvp-vs-vnext-features) + +--- + +## 1. Executive Summary + +### What It Is + +**MAUI Dev Tools Client** is a unified local tool and service API that detects, installs, repairs, and automates all native dependencies required for .NET MAUI development. It exposes device and simulator helpers that human users, IDEs, and AI agents can invoke safely and consistently. + +### Why It Exists + +Setting up a .NET MAUI development environment is one of the most significant friction points for new and experienced developers alike. The current experience requires: + +- Manual installation of Android SDK, build-tools, emulators, and system images +- Manual installation and configuration of Xcode, simulators, and runtimes on macOS +- Troubleshooting cryptic errors when components are missing or misconfigured +- No unified way for IDEs or AI agents to query environment status or automate fixes + +This tool eliminates that friction by providing a single, authoritative source for environment health and automated remediation. + +### Who It's For + +| Persona | Primary Value | +|---------|---------------| +| MAUI Developer (Windows) | One-command setup for Android development | +| MAUI Developer (macOS) | Unified setup for Android + iOS/Mac Catalyst | +| CI Engineer | Headless, automatable environment provisioning | +| AI Agent | Structured APIs for querying and fixing environment issues | +| IDE (VS/VS Code) | Fast, reliable environment checks with actionable fixes | + +--- + +## 2. Problem Statement + +### Current Pain Points + +1. **Fragmented Tooling**: Developers must use `sdkmanager`, `avdmanager`, `xcrun`, `simctl`, and `xcode-select` separately—each with different UX patterns, output formats, and error handling. + +2. **Silent Failures**: Missing or misconfigured dependencies often surface as cryptic build errors deep in MSBuild logs, not as clear diagnostic messages. + +3. **No Unified "Doctor"**: Unlike Flutter's `flutter doctor`, there's no single command that checks all MAUI prerequisites and offers fixes. + +4. **IDE Integration Gap**: Visual Studio and VS Code must independently implement detection and installation logic, leading to inconsistent experiences. + +5. **AI Agent Blind Spot**: AI coding assistants cannot reliably query environment state or propose fixes because there's no structured API. + +6. **CI Complexity**: Setting up MAUI builds in CI requires extensive scripting and platform-specific knowledge. + +### Impact + +- High abandonment rate for new MAUI developers during setup +- Increased support burden for environment-related issues +- Duplicated effort across IDE teams +- AI agents cannot effectively assist with environment problems + +--- + +## 3. Goals, Non-Goals & Personas + +### Goals + +| ID | Goal | Success Metric | +|----|------|----------------| +| G1 | Reduce MAUI setup time to under 10 minutes | Time-to-first-build < 10 min for 90% of users | +| G2 | Provide a single "doctor" command that identifies all issues | 100% coverage of common setup issues | +| G3 | Enable one-click/one-command fixes for detected issues | >80% of issues auto-fixable | +| G4 | Expose structured APIs for IDE and AI agent consumption | JSON output with stable schema | +| G5 | Support headless operation for CI environments | All commands runnable non-interactively | + +### Non-Goals + +| ID | Non-Goal | Rationale | +|----|----------|-----------| +| NG1 | Replace `dotnet` CLI | This tool complements, not replaces, the .NET CLI | +| NG2 | Full Apple signing/provisioning management | Complex domain; integrate with existing tools instead | +| NG3 | Linux host support (MVP) | MAUI mobile development requires Windows or macOS | +| NG4 | Physical iOS device provisioning | Requires Apple Developer account; out of scope for MVP | +| NG5 | Manage Visual Studio installation | VS has its own installer; we detect, not manage | + +### Design Principles + +**DP1: Delegate to Native Toolchains** — Do not reimplement. Use `sdkmanager`, `avdmanager`, `adb`, `emulator` for Android; `xcrun simctl`, `xcode-select` for Apple; Windows SDK installer for Windows. Native tools are authoritative, reduce maintenance burden, and ensure consistency. + +**DP2: Reuse & Consolidate** — Leverage [`dotnet/android-tools`](https://github.com/dotnet/android-tools) for SDK/JDK discovery. Move proven code from `android-platform-support` (internal) to the public `android-tools` package for JDK installation, SDK bootstrap, and license acceptance. + +**DP3: Stateless Architecture** — Each command reads state, acts, and exits. Uses file-system caching (`~/.maui/cache/`) with TTLs for performance. + +**DP4: Machine-First Output** — Every command supports `--json` with stable schema. Priority: AI agents > CI/CD > humans. Required flags: `--json`, `--dry-run`, `--interactive`. + +### Target Personas + +| Persona | Profile | Key Need | +|---------|---------|----------| +| **Windows Developer** | .NET dev, new to Android | One-click install of all Android dependencies | +| **macOS Developer** | Building iOS apps, has Xcode | Detection of runtime/simulator state, guided fixes | +| **CI Engineer** | DevOps configuring pipelines | `--interactive false`, JSON output, deterministic exit codes | +| **AI Agent** | GitHub Copilot, IDE assistants | Structured JSON for diagnosis, permission-gated fixes | + + +--- + +## 4. Functional Requirements + +### 4.1 Doctor Capability + +| ID | Requirement | Priority | +|----|-------------|----------| +| FR-D1 | Detect .NET SDK version and MAUI workload installation status | P0 | +| FR-D2 | Detect Android SDK location and installed components | P0 | +| FR-D3 | Detect Android build-tools, platform-tools, and emulator presence | P0 | +| FR-D4 | Detect Xcode installation (full Xcode.app, not just CLI Tools), version, and selected developer directory | P0 | +| FR-D5 | Detect installed iOS/macOS runtimes and simulators | P0 | +| FR-D6 | Detect Windows SDK installation and Developer Mode status (on Windows) | P1 | +| FR-D7 | Produce human-readable output with color-coded status (with text fallback for accessibility) | P0 | +| FR-D8 | Produce machine-readable JSON output with stable schema | P0 | +| FR-D9 | Provide `--fix` flag to automatically remediate fixable issues | P0 | +| FR-D10 | Prompt for confirmation before downloads >100MB | P0 | +| FR-D11 | Support `--platform` filter (`android`, `ios`, `maccatalyst`, `windows`) — multiple allowed | P1 | +| FR-D12 | Verify available disk space before attempting large downloads | P0 | +| FR-D13 | Support `--fix ` for targeted fixes | P1 | +| FR-D14 | Detect multiple SDK installations and report conflicts | P1 | + +### 4.2 Android Management + +| ID | Requirement | Priority | +|----|-------------|----------| +| FR-A1 | List connected devices and running emulators | P0 | +| FR-A2 | List installed SDK packages with version info | P0 | +| FR-A3 | Install SDK packages by name or alias (e.g., `--recommended`) | P0 | +| FR-A4 | List available emulators | P0 | +| FR-A5 | Create emulator with specified device profile and system image | P0 | +| FR-A6 | Start emulator and wait for boot completion | P0 | +| FR-A7 | Stop running emulator | P1 | +| FR-A8 | Cold boot emulator (wipe runtime state) | P1 | +| FR-A9 | Wipe emulator data | P2 | +| FR-A10 | Stream device logs with filtering | P1 | +| FR-A11 | Install APK to device/emulator | P1 | +| FR-A12 | Uninstall package from device/emulator | P2 | +| FR-A13 | Capture screenshot from device/emulator | P0 | +| FR-A14 | Install full Android environment (JDK + SDK) from scratch | P0 | +| FR-A15 | Detect JDK installation and version | P0 | +| FR-A16 | Install OpenJDK if missing (default: version 21) | P0 | +| FR-A17 | Use platform-appropriate default paths when env vars not set | P0 | + +### 4.3 Apple (Xcode) Management + +| ID | Requirement | Priority | +|----|-------------|----------| +| FR-X1 | List available simulators with runtime/device type info | P0 | +| FR-X2 | Filter simulators by runtime, device type, or state | P0 | +| FR-X3 | Start simulator by UUID or name | P0 | +| FR-X4 | Stop simulator | P0 | +| FR-X5 | Create simulator with specified runtime and device type | P0 | +| FR-X6 | Delete simulator | P2 | +| FR-X7 | List available runtimes | P0 | +| FR-X8 | Install runtime (guide user if manual steps needed) | P1 | +| FR-X9 | Capture screenshot from simulator | P0 | +| FR-X10 | Stream simulator/device logs | P1 | +| FR-X11 | Validate basic signing prerequisites (team ID, certificate presence) | P2 | +| FR-X12 | Open Simulator.app with specific device | P1 | +| FR-X13 | List all Xcode installations with version, build number, and selected status (`xcode list`) | P0 | +| FR-X14 | Switch active Xcode installation (`xcode select `) | P0 | +| FR-X15 | Detect Xcode beta installations at `/Applications/Xcode-beta.app` | P2 | + +### 4.4 Windows Management + +| ID | Requirement | Priority | +|----|-------------|----------| +| FR-W1 | Detect Windows SDK installation and version | P1 | +| FR-W2 | Detect Developer Mode enabled status | P0 | +| FR-W3 | Guide user to enable Developer Mode if disabled | P0 | +| FR-W4 | Detect Visual Studio installation and MAUI workload | P1 | +| FR-W5 | Detect Hyper-V availability for Android emulation | P1 | +| FR-W6 | Detect Windows App SDK dependencies | P2 | + +### 4.5 Cross-Platform Screenshot + +| ID | Requirement | Priority | +|----|-------------|----------| +| FR-S1 | Unified `screenshot` command across all platforms | P0 | +| FR-S2 | Auto-detect target device if only one is available | P0 | +| FR-S3 | Support `--device` flag for explicit device selection | P0 | +| FR-S4 | Support `--output` flag for file path (default: timestamped file) | P0 | +| FR-S5 | Support `--wait` flag to delay capture | P1 | +| FR-S6 | Support `--format` flag (png, jpg) | P2 | +| FR-S7 | Return file path in JSON output | P0 | + +### 4.6 Device Listing (Unified) + +| ID | Requirement | Priority | +|----|-------------|----------| +| FR-DL1 | `device list` shows all available devices across platforms | P0 | +| FR-DL2 | Include device type (physical/emulator/simulator), platform, state | P0 | +| FR-DL3 | Include unique identifier (serial/UDID) for targeting | P0 | +| FR-DL4 | Support `--platform` filter (`android`, `ios`, `maccatalyst`, `windows`) | P1 | +| FR-DL5 | Support `--json` output | P0 | + +### 4.7 Install State Machine + +**Critical**: The tool must handle the "install gap" — the chicken-and-egg problem where native tools (sdkmanager, xcrun) don't exist yet. + +#### Platform Bootstrap States + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ MISSING │────▶│ DOWNLOADING │────▶│ INSTALLING │────▶│ READY │ +└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ + │ │ │ │ + │ │ │ │ + ▼ ▼ ▼ ▼ + User action Progress Progress Operational + required reporting reporting (delegate to + (or auto-fix) native tools) +``` + +#### Android Install + +The tool can fully install an Android development environment from scratch, including JDK and SDK installation. + +**Dependency Order**: JDK must be installed before SDK (sdkmanager requires Java). + +``` +┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ +│ JDK Check │────▶│ JDK Install │────▶│ SDK Install │────▶│ READY │ +└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ + │ │ │ │ + Missing? Download Download Operational + OpenJDK 21 cmdline-tools (delegate) +``` + +**Default Installation Paths** (when env vars not set): + +| Platform | JDK Path | SDK Path | +|----------|----------|----------| +| macOS | `~/Library/Developer/Android/jdk` | `~/Library/Developer/Android/sdk` | +| Windows | `%LOCALAPPDATA%\Android\jdk` | `%LOCALAPPDATA%\Android\sdk` | + +**Install States**: + +| State | Detection | Behavior | +|-------|-----------|----------| +| `JDK_MISSING` | No `java` in PATH, no JDK at default paths | Install OpenJDK 21 to default path | +| `SDK_MISSING` | `ANDROID_HOME` not set, no SDK at standard paths | Install command-line tools to default path | +| `PARTIAL` | SDK exists but `sdkmanager` missing/broken | Repair SDK or reinstall cmdline-tools | +| `READY` | `java -version` succeeds AND `sdkmanager --list` succeeds | Delegate all operations to native tools | + +**Install Command**: +```bash +# Full install: JDK + SDK + recommended packages +maui android install --accept-licenses + +# With custom paths +maui android install --jdk-path ~/my-jdk --sdk-path ~/my-sdk --accept-licenses + +# With specific packages (comma-separated) +maui android install --packages "platform-tools,build-tools;35.0.0,platforms;android-35" +``` + +This command: +1. Checks for JDK; if missing, downloads and installs OpenJDK 21 +2. Sets `JAVA_HOME` for the session (prints guidance for permanent setup) +3. Downloads Android command-line tools (if missing) +4. Accepts SDK licenses non-interactively (if `--accept-licenses`) +5. Installs specified packages (or default recommended set if `--packages` not provided) +6. Prints environment variable guidance (doesn't modify shell config) + +**JDK Management Commands**: +```bash +# Check JDK status +maui android jdk check + +# Install OpenJDK (default: version 21) +maui android jdk install +maui android jdk install --version 21 + +# List installed JDK versions +maui android jdk list +``` + +**Environment Variable Guidance Output**: +``` +✓ JDK installed to ~/Library/Developer/Android/jdk +✓ SDK installed to ~/Library/Developer/Android/sdk + +Add to your shell profile (~/.zshrc or ~/.bashrc): + + export JAVA_HOME="$HOME/Library/Developer/Android/jdk" + export ANDROID_HOME="$HOME/Library/Developer/Android/sdk" + export PATH="$JAVA_HOME/bin:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$PATH" +``` + +**Emulator Creation with Auto-Detection**: + +When `--package` is not specified, the tool automatically detects the most recent installed system image: + +```bash +# Auto-detect system image (uses highest API level installed) +maui android emulator create MyEmulator + +# Explicitly specify system image +maui android emulator create MyEmulator --package "system-images;android-35;google_apis;arm64-v8a" +``` + +#### Apple Install + +| State | Detection | Behavior | +|-------|-----------|----------| +| `MISSING` | No Xcode.app at `/Applications/Xcode*.app` | Error: "Install Xcode from App Store" (cannot auto-install today; could prompt user in future) | +| `CLI_ONLY` | Only Command Line Tools installed | Error: "Full Xcode required for simulators" | +| `READY` | `xcrun simctl list` succeeds | Delegate all operations to native tools | + +**Important**: Xcode itself cannot be installed programmatically today (App Store or interactive install with Apple ID credentials). The `install` command focuses on what _can_ be automated: +- Xcode license acceptance (`xcodebuild -license accept`) via `--accept-license` +- iOS simulator runtime installation via `--runtime ` +- In the future, could prompt the user to install Xcode + +```bash +# Check environment and report status +maui apple install + +# Accept Xcode license and install a specific runtime +maui apple install --accept-license --runtime 18.5 +``` + +This command: +1. Verifies Xcode installation (reports error with guidance if missing) +2. Optionally accepts Xcode license (`--accept-license`) +3. Lists installed runtimes +4. Optionally installs a specific iOS runtime (`--runtime `) +5. Reports overall status and next steps + +`maui apple check` provides a read-only status check without modifying anything. + +#### Windows Install + +| State | Detection | Behavior | +|-------|-----------|----------| +| `MISSING` | No Windows SDK detected | Provide download link | +| `NO_DEV_MODE` | Developer Mode disabled | Guide user to enable (requires Settings app) | +| `READY` | SDK present, Developer Mode enabled | Operational | + +--- + +## 5. Non-Functional Requirements + +### 5.1 Reliability + +| ID | Requirement | +|----|-------------| +| NFR-R1 | All operations must be idempotent (safe to retry) | +| NFR-R2 | Network failures must produce clear error messages with retry guidance | +| NFR-R3 | Partial failures during multi-step operations must leave system in consistent state | +| NFR-R4 | Tool must gracefully handle missing permissions | + +### 5.2 Observability + +| ID | Requirement | +|----|-------------| +| NFR-O1 | All operations must support `--verbose` flag for detailed logging | +| NFR-O2 | JSON output must include `correlation_id` for tracing | +| NFR-O3 | Long-running operations must emit progress events | +| NFR-O4 | (vNext) `diagnostic-bundle` command to collect all relevant logs and state | + +**Progress Reporting**: + +Long-running operations (install, SDK install, JDK install) emit step-by-step progress: + +Console output: +``` +[1/4] Checking JDK installation... +[2/4] Installing JDK 21... +[3/4] Checking SDK installation... +[4/4] Installing SDK packages: platform-tools, build-tools;35.0.0 +✓ Bootstrap completed successfully +``` + +JSON output (`--json`): +```json +{ + "type": "progress", + "step": 2, + "total_steps": 4, + "message": "Installing JDK 21...", + "percentage": 50 +} +``` + +IDE consumers can use the `type: "progress"` messages to update progress bars and status indicators. + +### 5.3 Performance + +| ID | Requirement | +|----|-------------| +| NFR-P1 | `doctor` command must complete in <5s when no network calls needed | +| NFR-P2 | Device list must complete in <2s | +| NFR-P3 | Read operations must use direct file parsing (not CLI wrappers) for performance | + +**Performance Implementation Notes**: +- Android SDK detection: Parse `package.xml` and `source.properties` directly instead of invoking `sdkmanager --list` (which has 3-10s JVM startup time) +- iOS simulator list: Use `xcrun simctl list -j` (fast native tool) +- Fall back to CLI tools only for write operations (install, create, etc.) + +**Shell Quoting Implementation Notes**: +- Package identifiers contain semicolons (e.g., `system-images;android-35;google_apis;arm64-v8a`) +- When calling `avdmanager` or `sdkmanager`, arguments with semicolons **SHOULD** be passed directly to the child process as an argument list (not via a shell) so that semicolons are not interpreted as command separators. +- If shell invocation is unavoidable, quoting **MUST** be documented per shell: + - POSIX shells (`bash`, `zsh`): `--package 'system-images;android-35;google_apis;arm64-v8a'` + - Windows `cmd.exe`: `--package "system-images;android-35;google_apis;arm64-v8a"` + - PowerShell: `--package 'system-images;android-35;google_apis;arm64-v8a'` +- Correct quoting prevents shell interpretation of semicolons as command separators. + +### 5.4 Security + +| ID | Requirement | +|----|-------------| +| NFR-S1 | Downloads must verify checksums before installation | +| NFR-S2 | Tool must never store or transmit credentials | +| NFR-S3 | Elevation must be requested explicitly with clear justification | +| NFR-S4 | AI agent calls must respect permission gates (see Security Model) | + +#### Elevation Model + +Some operations require OS-level elevation when targeting system-protected paths. The tool **never silently elevates** — it always detects the need first, then delegates to the platform's native elevation mechanism. + +**When Elevation is Required**: + +| Scenario | Platform | Example | +|----------|----------|---------| +| Android SDK/JDK install to system path | Windows | Installing to `C:\Program Files\Android\sdk` | +| Android SDK/JDK install to system path | macOS | Installing to `/opt/android-sdk` (rare — default is user home) | +| Xcode selection | macOS | `xcode-select -s` requires `sudo` | +| Xcode license acceptance | macOS | `xcodebuild -license accept` requires `sudo` | +| iOS runtime installation | macOS | `xcodebuild -downloadPlatform iOS` requires admin | +| Enable Developer Mode | Windows | Requires Settings app (no CLI elevation path) | + +**Windows Elevation Flow**: + +When the tool detects that the target install path requires elevation (e.g., `Program Files`): + +1. The tool detects the current process is **not elevated** +2. It launches a **new elevated process** via `ProcessStartInfo` with `Verb = "runas"`, which triggers the standard UAC prompt +3. The elevated child process performs the install operation +4. The parent process monitors the child and reports progress/result +5. If the user declines UAC, the tool returns error `E2001` + +``` +┌─────────────────────────────────────────────────────────────┐ +│ maui android install --sdk-path "C:\Program Files\Android\sdk" │ +├─────────────────────────────────────────────────────────────┤ +│ 1. Detect: target path requires elevation │ +│ 2. Prompt: "Installing to a system path requires admin │ +│ permissions. Continue? [Y/n]" │ +│ 3. Launch: elevated child process (UAC dialog appears) │ +│ 4. Child: performs SDK download + install │ +│ 5. Parent: streams progress from child, reports result │ +└─────────────────────────────────────────────────────────────┘ +``` + +**macOS Elevation Flow**: + +| Context | Mechanism | Details | +|---------|-----------|---------| +| Terminal | `sudo` | Tool re-invokes itself with `sudo` for the specific operation that needs it (e.g., `sudo xcode-select -s `) | +| IDE (e.g., VS Code) | OS-managed elevation | IDE invokes a privileged helper or re-launches the tool in an elevated context, relying on supported macOS mechanisms and system authentication UI | +| CI | Pre-authorized | CI agents typically run with required permissions; `--interactive` defaults to `false` when CI env vars are detected | + +``` +┌─────────────────────────────────────────────────────────────┐ +│ maui apple xcode select /Applications/Xcode.app │ +├─────────────────────────────────────────────────────────────┤ +│ 1. Detect: xcode-select requires sudo │ +│ 2. Invoke: sudo xcode-select -s /Applications/Xcode.app │ +│ 3. macOS shows system password prompt │ +│ 4. On success: report new active Xcode │ +│ 5. On failure: return E5001 with guidance │ +└─────────────────────────────────────────────────────────────┘ +``` + +**Default Paths Avoid Elevation**: + +By default, the tool installs to **user-writable paths** that do not require elevation: + +| Platform | Default JDK Path | Default SDK Path | Elevation Needed | +|----------|------------------|------------------|------------------| +| macOS | `~/Library/Developer/Android/jdk` | `~/Library/Developer/Android/sdk` | No | +| Windows | `%LOCALAPPDATA%\Android\jdk` | `%LOCALAPPDATA%\Android\sdk` | No | + +Elevation is only triggered when the user explicitly specifies a system path via `--sdk-path`, `--jdk-path`, or for macOS operations that inherently require `sudo` (Xcode selection, license acceptance, runtime installs). + +**Error on Elevation Denial**: + +```json +{ + "code": "E5001", + "category": "user", + "message": "Operation requires elevated permissions", + "context": { + "operation": "android.sdk.install", + "target_path": "C:\\Program Files\\Android\\sdk", + "platform": "windows" + }, + "remediation": { + "type": "user_action", + "manual_steps": [ + "Run the command from an elevated terminal (Run as Administrator)", + "Or install to a user-writable path: maui android install --sdk-path %LOCALAPPDATA%\\Android\\sdk" + ] + } +} +``` + +### 5.5 Privacy + +| ID | Requirement | +|----|-------------| +| NFR-PR1 | No PII in logs or telemetry | +| NFR-PR2 | File paths must be redacted in telemetry (keep structure only) | +| NFR-PR3 | Telemetry must be opt-in with clear disclosure | + +### 5.6 Network & Proxy Support + +| ID | Requirement | +|----|-------------| +| NFR-N1 | Respect system proxy settings (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) | + +--- + +## 6. Architecture + +### 6.1 High-Level Components + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Consumers │ +├─────────────┬─────────────┬─────────────┬─────────────┬─────────────────┤ +│ Terminal │ VS Code │ Visual │ AI Agent │ CI/CD │ +│ (Human) │ Extension │ Studio │ (Copilot) │ Pipeline │ +└──────┬──────┴──────┬──────┴──────┬──────┴──────┬──────┴────────┬────────┘ + │ │ │ │ │ + │ CLI │ CLI │ CLI │ CLI │ CLI + │ │ (--json) │ (--json) │ (--json) │ + ▼ ▼ ▼ ▼ ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ MAUI Dev Tools Client │ +├─────────────────────────────────────────────────────────────────────────┤ +│ ┌─────────────────────────────────────────────────────────────┐ │ +│ │ CLI Layer │ │ +│ │ (Argument parsing, output formatting, --json support) │ │ +│ └──────────────────────────────┬──────────────────────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ Core Services │ │ +│ ├──────────────┬──────────────┬──────────────┬─────────────────┤ │ +│ │ Doctor │ Device │ Artifact │ Logging │ │ +│ │ Service │ Manager │ Manager │ Service │ │ +│ └──────┬───────┴──────┬───────┴──────┬───────┴────────┬────────┘ │ +│ │ │ │ │ │ +│ ▼ ▼ ▼ ▼ │ +│ ┌──────────────────────────────────────────────────────────────┐ │ +│ │ Platform Providers │ │ +│ ├────────────────┬────────────────┬────────────────────────────┤ │ +│ │ Android │ Apple │ Windows │ │ +│ │ Provider │ Provider │ Provider │ │ +│ └────────────────┴────────────────┴────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────────────┐ +│ Native Toolchains │ +├───────────────────┬───────────────────┬─────────────────────────────────┤ +│ Android SDK │ Xcode/xcrun │ Windows SDK │ +│ (sdkmanager, │ (simctl, │ (vsdevcmd) │ +│ adb, avdmanager)│ xcode-select) │ │ +└───────────────────┴───────────────────┴─────────────────────────────────┘ +``` + +### 6.2 Component Descriptions + +#### CLI Layer +- Parses command-line arguments using `System.CommandLine` +- Maps commands to core service calls +- Formats output for human consumption (colors, tables, progress bars) +- Supports `--json` for machine-readable output +- Entry point: `maui` command + +#### Core Services + +| Service | Responsibility | +|---------|----------------| +| Doctor Service | Aggregates health checks from all providers; produces unified report | +| Device Manager | Unified device/emulator/simulator listing; dispatches to providers | +| Artifact Manager | Manages downloads, caching, and verification | +| Logging Service | Structured logging with correlation IDs; diagnostic bundle export | + +#### Platform Providers + +| Provider | Responsibility | +|----------|----------------| +| Android Provider | Wraps `sdkmanager`, `avdmanager`, `adb`, `emulator`. Uses [`Xamarin.Android.Tools.AndroidSdk`](https://github.com/dotnet/android-tools) for SDK/JDK discovery (see §6.8). Additional features (JDK install, SDK bootstrap, license acceptance) will be consumed from `android-tools` as they become available. | +| Apple Provider | Wraps `xcrun simctl`, `xcode-select`, `xcodebuild` | +| Windows Provider | Wraps Windows SDK detection and VS build tools | + +### 6.3 Data Flow: Doctor Command + +``` +User: maui doctor --json + │ + ▼ + ┌─────────┐ + │ CLI │ + └────┬────┘ + │ Parse args, determine output format + ▼ + ┌─────────────┐ + │ Doctor │ + │ Service │ + └──────┬──────┘ + │ Invoke each provider's health check + ├────────────────────────┬────────────────────────┐ + ▼ ▼ ▼ + ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ + │ Android │ │ Apple │ │ Windows │ + │ Provider │ │ Provider │ │ Provider │ + └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ + │ │ │ + ▼ ▼ ▼ + ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ + │ sdkmanager │ │ simctl │ │ VS Where │ + │ adb │ │xcode-select │ │ │ + └─────────────┘ └─────────────┘ └─────────────┘ + │ │ │ + └────────────────────────┴────────────────────────┘ + │ + ▼ Aggregate results + ┌─────────────┐ + │ Doctor │ + │ Service │ + └──────┬──────┘ + │ Format as JSON + ▼ + ┌─────────────┐ + │ stdout │ + └─────────────┘ +``` + +### 6.4 IDE Extension Integration + +> **See [IDE Integration](./maui-devtools-ide-integration.md)** for detailed VS Code and Visual Studio UI flows, status panels, and menu integrations. + +**Summary**: IDEs consume the `maui` CLI (VS Code, AI agents) or the underlying `android-tools` NuGet library directly (Visual Studio). On workspace open, they invoke environment checks (`maui apple check --json`, `maui android jdk check --json`), display issues in problems panels, and provide commands for environment setup with progress notifications. + +### 6.5 Migration from Existing Setups + +When an existing SDK is detected: + +1. **Validate** existing SDK health before offering modifications +2. **Adopt or Fresh**: Offer "adopt existing" vs "install fresh" options +3. **Non-Destructive**: Never delete or modify user's existing SDK without explicit consent +4. **Override Support**: `--sdk-path` for non-standard locations + +### 6.8 Shared Libraries & Code Reuse + +The Android Provider layer reuses the **[`Xamarin.Android.Tools.AndroidSdk`](https://github.com/dotnet/android-tools)** NuGet package (`dotnet/android-tools`) for SDK and JDK discovery. This library is the same shared component used by the .NET for Android build tooling and IDE extensions, ensuring consistent behavior across the ecosystem. + +#### What We Reuse from `Xamarin.Android.Tools.AndroidSdk` + +| Capability | Class | Why Reuse | +|-----------|-------|-----------| +| **Android SDK path discovery** | `AndroidSdkInfo` + `AndroidSdkBase` | Probes 15+ locations: `ANDROID_HOME`, `ANDROID_SDK_ROOT`, Windows registry (HKLM/HKCU for VS-installed SDKs), macOS Homebrew, Linux `/usr/lib/android-sdk`, Android Studio paths. Validates by checking for `adb` executable. | +| **JDK discovery** | `JdkInfo` + `*JdkLocations.cs` | Finds Microsoft OpenJDK, Eclipse Adoptium, Azul, Oracle, VS-bundled JDKs. Checks Windows registry (32/64-bit views), macOS `/usr/libexec/java_home`, Linux `update-java-alternatives`. Returns version, vendor, home path. | +| **JDK installation** | `JdkInstaller` *(planned)* | Based on `android-platform-support`'s `JavaDependencyInstaller`. Downloads Microsoft OpenJDK from manifest feed, extracts, validates. Will be moved to `android-tools`. | +| **SDK bootstrap & management** | `SdkManager` *(planned)* | New implementation inspired by `android-platform-support`'s SDK installer. Downloads and unzips command-line tools from the manifest feed, then uses the extracted `sdkmanager` for package operations. Will be moved to `android-tools`. | +| **SDK path validation** | `AndroidSdkBase.ValidateAndroidSdkLocation()` | Executable-based validation (checks for `adb`) rather than simple directory existence. | +| **Process/executable utilities** | `ProcessUtils` | PATHEXT-aware executable discovery (`FindExecutablesInDirectory`). | +| **Android version mapping** | `AndroidVersion` / `AndroidVersions` | Maps API levels ↔ version names/codenames for human-readable output. | + +#### What We Reuse from `android-platform-support` (Internal) + +The **`android-platform-support`** repository (internal, `devdiv/android-platform-support`) contains the shared SDK installer backend used by VS for Mac, the Android SDK Manager UI, and the Device Manager. Key components we can reuse or draw from: + +| Capability | Project / Class | Why Reuse | +|-----------|----------------|-----------| +| **Manifest feed parsing** | `XamarinRepository` + `GoogleV2Repository` | Parses the Xamarin Android Manifest Feed and Google's `repository2-3.xml`. Provides download URLs, checksums, and version metadata — no hardcoded URLs needed (see §6.8.1). | +| **License acceptance** | `AndroidLicensesStorage` | Battle-tested subprocess orchestration of `sdkmanager --licenses`. Handles interactive Y/N prompts, writes license hashes to `$SDK_ROOT/licenses/`, platform-specific `sdkmanager.bat` vs `sdkmanager`. | +| **AVD discovery** | `Mono.AndroidTools` / `AndroidVirtualDeviceManager` | Filesystem watcher-based AVD enumeration. Read-only; create/start/stop/delete remain in DevTools. | +| **Manifest caching** | `LocalManifestProvider` | Offline/CI support: caches downloaded manifests to disk with fallback URLs. | +| **Progress reporting** | `Xamarin.Installer.Common` / `InstallationProgressEventArgs` | Structured progress events (0-100%) for CLI and IDE consumption. | + +> **Note:** `android-platform-support` also contains `AndroidSDKInstaller` (full SDK install pipeline) and `Mono.AndroidTools` / `AdbClient` (raw TCP ADB protocol). These are not reused initially — DevTools will bootstrap by unzipping command-line tools from the manifest feed and then delegating to `sdkmanager` for package operations, and will use the `adb` CLI for device communication. We may revisit reusing these components in the future. +> +> JDK installation (`JavaDependencyInstaller`) and `sdkmanager` wrapper logic will be contributed from `android-platform-support` to the public `dotnet/android-tools` package, where DevTools will consume them (see table above). + +#### 6.8.1 Manifest-Driven Downloads & Checksum Verification + +**No download URLs are hardcoded.** All SDK and JDK download URLs are resolved from manifest feeds at runtime: + +| Feed | URL | Contents | +|------|-----|----------| +| **Xamarin Android Manifest** | `https://aka.ms/AndroidManifestFeed/d{version}` (e.g., `d18-0`) | JDK archives (Microsoft OpenJDK), platform-tools, command-line tools, emulator — with per-platform/architecture URLs and SHA-1 checksums | +| **Google SDK Repository** | `https://dl.google.com/android/repository/repository2-3.xml` | SDK platforms, build-tools, system images, add-ons — Google's official package index with SHA-1 checksums | + +Every download is verified against the manifest's checksum before installation: + +``` +1. Resolve package → manifest feed lookup +2. Download archive → temp file +3. Compute SHA-1 of downloaded file +4. Compare against manifest checksum → mismatch = abort + error +5. Extract (unzip) to SDK directory +6. For SDK packages: delegate to extracted sdkmanager for install/update +``` + +**Bootstrap flow for `android install`:** +1. Read manifest feed → resolve command-line tools URL + checksum for current OS/arch +2. Download & SHA-1 verify command-line tools archive +3. Unzip to `$ANDROID_HOME/cmdline-tools/latest/` +4. Use the now-available `sdkmanager` to install remaining packages (platforms, build-tools, emulator, system images) + +This ensures: +- **No stale URLs** — feed is updated centrally via aka.ms redirect; DevTools always gets current URLs +- **Tamper detection** — SHA-1 verification catches corrupted or modified downloads +- **Consistency** — same manifest feed already used by VS SDK Manager, VS for Mac, and `android-platform-support` + +The manifest feed parsing infrastructure already exists in `android-platform-support`'s `XamarinRepository` and `GoogleV2Repository` classes. + +#### What Remains in MAUI DevTools (Not in Shared Libraries) + +| Capability | Rationale | +|-----------|-----------| +| **SDK bootstrap (command-line tools)** | DevTools downloads and unzips command-line tools from the manifest feed to bootstrap a fresh SDK. Subsequent package operations use the `sdkmanager` wrapper from `android-tools`. | +| **ADB device communication** | DevTools shells out to the `adb` CLI for device listing, logcat streaming, and screenshot capture. | +| **CLI command routing** | `System.CommandLine`-based CLI layer, output formatting, `--json`/`--verbose` modes. | +| **`avdmanager` / `emulator` lifecycle** | AVD create/start/stop/delete and emulator lifecycle management. | +| **`device screenshot`** | DevTools uses `adb exec-out screencap -p` for Android screenshots. | +| **OS elevation model** | UAC/sudo handling for SDK installs into protected paths (see §5.4). | +| **Apple & Windows providers** | Entirely DevTools-specific; shared Android libraries are Android-only. | + +#### Contributing to `dotnet/android-tools` + +Capabilities currently in `android-platform-support` (internal) will be moved to the public `Xamarin.Android.Tools.AndroidSdk` package in `dotnet/android-tools`: + +| Capability | Source in `android-platform-support` | Benefit | +|-----------|--------------------------------------|---------| +| **JDK installation** | `JavaDependencyInstaller` | IDEs, build tasks, and DevTools can auto-install missing JDKs instead of just reporting errors. | +| **SDK bootstrap & management** | `AndroidSDKInstaller` | Shared API for downloading command-line tools and managing SDK packages — used by DevTools CLI, IDE extensions, and CI. | +| **License acceptance** | `AndroidLicensesStorage` | Unattended CI scenarios across all .NET Android tooling. | + +DevTools will consume these from the `Xamarin.Android.Tools.AndroidSdk` NuGet package once moved. + +This approach ensures DevTools benefits from the battle-tested discovery logic in `android-tools` while contributing new capabilities back to the ecosystem over time. + +### 6.9 Error Contract Specification + +**This is the highest-priority architectural element.** Every consumer (AI agents, CI pipelines, IDEs, humans) depends on predictable error handling. + +#### Error Taxonomy + +Errors are classified into four categories: + +| Category | Prefix | Responsibility | Example | +|----------|--------|----------------|---------| +| **Tool** | `E1xxx` | Bug in this tool | E1001: Internal state corruption | +| **Platform** | `E2xxx` | Native tool or SDK issue | E2001: sdkmanager license not accepted | +| **User** | `E3xxx` | User action required | E3001: Xcode not installed | +| **Unknown** | `E0xxx` | Source cannot be reliably determined (e.g., truncated or partial native output) | E0001: Unknown native tool failure | + +#### Error Object Schema + +**Every error MUST be expressible as this JSON structure; `category` MUST be one of `tool`, `platform`, `user`, or `unknown`.** + +```json +{ + "code": "E2001", + "category": "platform", + "severity": "error", + "message": "Android SDK licenses not accepted", + "native_error": "Warning: License for package Android SDK Platform 34 not accepted.", + "context": { + "sdk_path": "/Users/dev/Library/Android/sdk", + "package": "platforms;android-34" + }, + "remediation": { + "type": "auto_fixable", + "command": "maui android sdk accept-licenses", + "manual_steps": null + }, + "docs_url": "https://learn.microsoft.com/dotnet/maui/troubleshoot/E2001", + "correlation_id": "7f3d2a1b-..." +} +``` + +#### Remediation Types + +| Type | Meaning | AI Agent Behavior | +|------|---------|-------------------| +| `auto_fixable` | Tool can fix this automatically | Execute `remediation.command` with user permission | +| `user_action` | User must take manual steps | Display `remediation.manual_steps`, cannot auto-fix | +| `terminal` | Cannot be fixed (e.g., unsupported OS) | Report error, suggest alternatives | +| `unknown` | Tool doesn't recognize this error | Escalate to Copilot Handoff | + +#### Error Code Registry (Partial) + +| Code | Category | Message | Remediation Type | +|------|----------|---------|------------------| +| `E1001` | tool | Internal error | terminal | +| `E2001` | platform | SDK licenses not accepted | auto_fixable | +| `E2002` | platform | sdkmanager not found | auto_fixable (install) | +| `E2003` | platform | xcrun failed | user_action | +| `E2004` | platform | Emulator acceleration unavailable | user_action | +| `E3001` | user | Xcode not installed | user_action | +| `E3002` | user | Developer Mode not enabled | user_action | +| `E3003` | user | Insufficient disk space | user_action | +| `E3004` | user | Network unavailable | user_action | + +#### Unknown Error Handling + +When the tool encounters an error it doesn't recognize: + +```json +{ + "code": "E0000", + "category": "unknown", + "severity": "error", + "message": "Unexpected error from native tool", + "native_error": "", + "remediation": { + "type": "unknown", + "command": null, + "manual_steps": null + }, + "copilot_handoff": { + "eligible": true, + "context": { + "doctor_report": { ... }, + "failed_command": "maui android emulator create ...", + "environment": { ... }, + "native_tool_output": "..." + } + } +} +``` + +This is the **Copilot escalation trigger** — structured data that AI agents can consume to diagnose novel issues. + +#### Exit Code Mapping + +| Exit Code | Meaning | Contains | +|-----------|---------|----------| +| 0 | Success | Result data | +| 1 | Partial success | Result + warnings | +| 2 | Operation failed | Error objects | +| 3 | Permission denied | Error + elevation guidance | +| 4 | User cancelled | Cancellation reason | +| 5 | Resource not found | Error + suggestions | +| 126 | Command not executable | Error | +| 127 | Command not found | Error | + +#### Structured Output Contract + +**All commands MUST support these output modes:** + +```bash +# Default: Human-readable (stderr for errors, stdout for results) +maui doctor + +# Machine-readable: JSON to stdout (errors included in JSON, not stderr) +maui doctor --json + +# CI mode: JSON output, no prompts +maui doctor --json --interactive false +``` + +**JSON output envelope:** + +```json +{ + "success": false, + "correlation_id": "...", + "duration_ms": 1234, + "result": null, + "errors": [ { ... } ], + "warnings": [ { ... } ] +} +``` + +--- + +## 7. Public API Surface + +### 7.1 CLI Commands + +The tool is invoked as `maui ` as a standalone CLI tool. Platform-specific commands use the target framework moniker pattern (`ios`, `android`, `maccatalyst`, `windows`). + +#### Command Hierarchy + +``` +maui +├── doctor # Check environment health +│ ├── --fix # Auto-fix all detected issues +│ ├── --platform

# Filter: android, ios, maccatalyst, windows +│ ├── --json # Output as JSON +│ └── --interactive false # Disable prompts (auto-detected in CI) +│ +├── device +│ ├── list # List all devices across platforms +│ │ ├── --platform # Filter by platform (android, ios, maccatalyst, windows) +│ │ └── --json # Output as JSON +│ ├── screenshot # Capture screenshot +│ │ ├── --device # Target device +│ │ ├── --output # Output file +│ │ ├── --wait # Delay before capture +│ │ └── --format # png, jpg +│ └── logs # Stream logs from device (unified across platforms) +│ ├── --device # Device identifier (required) +│ ├── --filter # Filter expression (platform-specific) +│ ├── --maui-only # Filter to MAUI-related logs only +│ └── --since

# JDK installation directory +│ │ ├── --jdk-version # JDK version (default: 21) +│ │ └── --sdk-path # SDK installation directory +│ ├── jdk # JDK management +│ │ ├── check # Check JDK installation status +│ │ ├── install # Install OpenJDK +│ │ │ ├── --version # JDK version (default: 21) +│ │ │ └── --path # Installation directory +│ │ └── list # List installed JDK versions +│ ├── sdk +│ │ ├── list # List SDK packages +│ │ │ ├── --available # Show packages available for install +│ │ │ └── --all # Show both installed and available +│ │ ├── install # Install package(s) - comma-separated +│ │ ├── accept-licenses # Accept all SDK licenses +│ │ └── uninstall # Uninstall package +│ └── emulator +│ ├── list # List emulators +│ ├── create # Create emulator +│ │ ├── --name # Emulator name +│ │ ├── --device # Device profile +│ │ ├── --package # System image (optional, auto-detects latest) +│ │ └── --force # Overwrite existing +│ ├── start # Start emulator +│ │ ├── --name # Emulator name +│ │ ├── --cold-boot # Cold boot +│ │ └── --wait # Wait for boot +│ ├── stop # Stop emulator +│ │ └── # Emulator name +│ └── delete # Delete emulator +│ └── --name # Emulator name +│ +├── apple # Apple platform commands (macOS only) +│ ├── install # Set up Apple environment (license, runtimes) +│ │ ├── --accept-license # Accept Xcode license +│ │ └── --runtime # iOS runtime version to install +│ ├── check # Check Xcode, runtimes, and environment status +│ ├── simulator +│ │ ├── list # List simulators +│ │ │ ├── --runtime # Filter by runtime +│ │ │ ├── --device-type # Filter by device type +│ │ │ └── --state # Filter: booted, shutdown +│ │ ├── create # Create simulator +│ │ │ ├── --name # Simulator name +│ │ │ ├── --runtime # Runtime identifier +│ │ │ └── --device-type # Device type identifier +│ │ ├── start # Start simulator +│ │ │ └── # Simulator UDID +│ │ ├── stop # Stop simulator +│ │ │ └── # Simulator UDID +│ │ └── delete # Delete simulator +│ │ └── # Simulator UDID +│ ├── runtime +│ │ ├── check # Check runtime installation status +│ │ ├── list # List runtimes +│ │ │ └── --all # Show all (installed + available) +│ │ └── install # Install iOS runtime +│ │ └── # Runtime version +│ └── xcode # Xcode installation management +│ ├── check # Check Xcode installation and license +│ ├── list # List installed Xcode versions +│ ├── select # Switch active Xcode installation +│ └── accept-license # Accept Xcode license agreement +│ +├── windows # Windows-specific commands (Windows only) +│ ├── sdk +│ │ └── list # List Windows SDK installations +│ └── developer-mode +│ ├── status # Check Developer Mode status +│ └── enable # Guide to enable Developer Mode +│ +└── --version # Show version +``` + +**Command Examples**: +```bash +# Cross-platform commands +maui doctor +maui doctor --fix +maui device list # List all devices (physical + emulators + simulators) +maui device list --platform android # Android devices and emulators +maui device list --platform ios # iOS simulators and physical devices +maui device list --platform maccatalyst # Mac Catalyst devices +maui device screenshot --device emulator-5554 + +# Android-specific +maui android sdk install platforms;android-34 +maui android emulator create --name Pixel_8 --device pixel_8 +maui android emulator start --name Pixel_8 --wait +maui device logs --device emulator-5554 + +# Apple-specific (macOS only) +maui apple install # Check environment, report status +maui apple install --accept-license # Also accept Xcode license +maui apple install --accept-license --runtime 18.5 # Accept license + install runtime +maui apple check # Read-only status check +maui apple simulator list +maui apple simulator start +maui apple runtime check +maui apple runtime list +maui apple runtime install 18.5 # Install specific runtime +maui apple xcode check +maui apple xcode list +maui apple xcode select /Applications/Xcode.app +maui apple xcode accept-license + +# Windows-specific +maui windows developer-mode status +``` + +#### Global Options (Available on All Commands) + +> **Design Principle DP4**: Every command MUST support `--json` output with a stable, versioned schema. The primary consumer is AI agents, not humans. + +| Option | Description | Required | +|--------|-------------|----------| +| `--json` | Output as JSON (machine-readable) | **Mandatory on all commands** ✅ | +| `--dry-run` | Show what would be done without executing | **Mandatory on write commands** ✅ | +| `--interactive` | Control interactive prompts (default: `true` for terminals, `false` in CI or when output is redirected — see below) | **Mandatory on all commands** ✅ | +| `--verbose` / `-v` | Enable verbose logging | Optional ✅ | +| `--correlation-id` | Set correlation ID for tracing | Optional (vNext) | +| `--offline` | Skip network operations; use cached data only | Optional (vNext) | + +**`--interactive` Detection (aligned with `dotnet` CLI)**: + +The `--interactive` flag follows the same pattern as the `dotnet` CLI ([`CommonOptions.CreateInteractiveOption`](https://github.com/dotnet/sdk/blob/main/src/Cli/Microsoft.DotNet.Cli.Definitions/Common/CommonOptions.cs)): + +- **Default: `true`** when running in a terminal (stdin/stdout not redirected, no CI env vars detected) +- **Default: `false`** when CI environment is detected OR `Console.IsOutputRedirected` is `true` +- **CI detection**: checks well-known environment variables — `TF_BUILD` (Azure Pipelines), `GITHUB_ACTIONS`, `CI` (generic), `TRAVIS`, `CIRCLECI`, `TEAMCITY_VERSION`, AWS CodeBuild (`CODEBUILD_BUILD_ID` + `AWS_REGION`), Jenkins (`BUILD_ID` + `BUILD_URL`), Google Cloud Build (`BUILD_ID` + `PROJECT_ID`), JetBrains Space (`JB_SPACE_API_URL`) +- **Explicit override**: `--interactive false` to suppress prompts, `--interactive` to force prompts in CI +- Accepts an optional boolean argument (`--interactive true`, `--interactive false`) or acts as a zero-arity flag (`--interactive` = `true`) + +When `--interactive` is `false`: +- No stdin prompts (fail with error if input is required and not provided via flags) +- Operations that require confirmation (e.g., downloads >100MB) must use `--accept-license` or `--yes` flags +- All required parameters must be provided via command-line arguments + +**`--dry-run` Mode Output**: +```json +{ + "dry_run": true, + "planned_operations": [ + { "action": "install", "target": "platforms;android-34", "size_mb": 150 }, + { "action": "install", "target": "build-tools;34.0.0", "size_mb": 55 } + ], + "estimated_duration_seconds": 120, + "requires_approval": true, + "approval_reason": "Downloads exceed 100MB" +} +``` + +#### Platform Filter Values + +The `--platform` flag accepts these values, aligned with .NET MAUI target framework monikers: + +| Value | Matches | Available On | +|-------|---------|--------------| +| `android` | Android physical devices and emulators | All hosts | +| `ios` | iOS simulators and physical devices | macOS only | +| `maccatalyst` | Mac Catalyst apps | macOS only | +| `windows` | Windows devices | Windows only | + +Multiple values can be specified: `--platform android --platform ios` + +#### Exit Code Standard + +All commands follow a consistent exit code scheme: + +| Code | Meaning | When Used | +|------|---------|-----------| +| 0 | Success / Healthy | Operation completed successfully | +| 1 | Partial success / Issues found | `doctor` found issues; operation completed with warnings | +| 2 | Operation failed | Command failed (network error, invalid input, etc.) | +| 3 | Permission denied | Elevation required but not granted | +| 4 | User canceled | User declined confirmation prompt | +| 5 | Resource not found | Requested device/emulator/simulator not found | +| 126 | Command not executable | Binary not found or not executable | +| 127 | Command not found | Unknown subcommand | + +#### Command Table + +| Command | Description | Inputs | Output | Exit Codes | +|---------|-------------|--------|--------|------------| +| `maui doctor` | Check environment health | `--fix`, `--platform`, `--json` | Status report | 0=healthy, 1=issues, 2=error | +| `maui device list` | List available devices | `--platform`, `--json` | Device list | 0=success, 2=error | +| `maui device screenshot` | Capture screenshot | `--device`, `--output`, `--wait` | File path | 0=success, 5=no device, 2=error | +| `maui android sdk list` | List SDK packages | `--available`, `--all`, `--json` | Package list | 0=success, 2=error | +| `maui android sdk install` | Install SDK package | ``, `--accept-licenses` | Progress, result | 0=success, 5=not found, 2=error | +| `maui android emulator create` | Create emulator | `--name`, `--device`, `--package` | Emulator name | 0=success, 1=exists, 2=error | +| `maui android emulator start` | Start emulator | `--name`, `--wait`, `--cold-boot` | Device serial | 0=success, 5=not found, 2=error | +| `maui android emulator stop` | Stop emulator | `` | Status | 0=success, 5=not found, 2=error | +| `maui android emulator delete` | Delete emulator | `--name` | Status | 0=success, 5=not found, 2=error | +| `maui apple simulator list` | List simulators | `--runtime`, `--device-type`, `--state` | Simulator list | 0=success, 2=error | +| `maui apple simulator start` | Start simulator | `` | UDID | 0=success, 5=not found, 2=error | +| `maui apple simulator stop` | Stop simulator | `` | Status | 0=success, 5=not found, 2=error | +| `maui apple simulator create` | Create simulator | ` ` | UDID | 0=success, 2=error | +| `maui apple simulator delete` | Delete simulator | `` | Status | 0=success, 5=not found, 2=error | +| `maui apple runtime list` | List iOS runtimes | `--all`, `--json` | Runtime list | 0=success, 2=error | +| `maui apple runtime check` | Check runtime status | `--json` | Status report | 0=success, 2=error | +| `maui apple runtime install` | Install iOS runtime | `` | Progress, result | 0=success, 2=error | +| `maui apple xcode check` | Check Xcode status | `--json` | Status report | 0=success, 2=error | +| `maui apple xcode list` | List Xcode installations | `--json` | Installation list | 0=success, 2=error | +| `maui apple xcode select` | Switch active Xcode | `` | Confirmation | 0=success, 3=permission denied | +| `maui apple xcode accept-license` | Accept Xcode license | `--json` | Status | 0=success, 3=permission denied | +| `maui apple install` | Set up Apple environment | `--accept-license`, `--runtime` | Progress, result | 0=success, 2=error | +| `maui apple check` | Read-only environment status | `--json` | Status report | 0=success, 2=error | +| `maui android sdk accept-licenses` | Accept SDK licenses | `--json` | Status | 0=success, 2=error | + +### 7.2 JSON Output Schemas + +#### MauiDevice Schema + +The unified device model for all platforms (physical devices, emulators, simulators): + +```json +{ + "name": "iPhone 15 Pro", + "identifier": "12345678-1234-1234-1234-123456789ABC", + "emulator_id": null, + "platforms": ["ios", "maccatalyst"], + "version": "18.5", + "version_name": "18.5", + "manufacturer": "Apple", + "model": "iPhone 15 Pro", + "sub_model": "Pro", + "idiom": "phone", + "platform_architecture": "arm64", + "runtime_identifiers": ["ios-arm64", "maccatalyst-arm64"], + "architecture": "arm64", + "is_emulator": true, + "is_running": true, + "connection_type": "local", + "type": "Simulator", + "state": "Booted", + "details": {} +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `name` | string | Display name (required) | +| `identifier` | string | Unique ID — AVD name (Android emulator), serial (Android physical), UDID (iOS) (required) | +| `emulator_id` | string? | AVD name for Android emulators | +| `platforms` | string[] | Supported platforms (required) | +| `version` | string? | API level for Android (e.g., `"35"`), OS version for iOS (e.g., `"18.5"`) | +| `version_name` | string? | OS version number without platform prefix (e.g., `"15.0"` not `"Android 15.0"`) | +| `manufacturer` | string? | Device manufacturer (`"Google"` for emulators, `ro.product.manufacturer` for physical) | +| `model` | string? | Device model (e.g., `"Pixel 8"`, `"iPhone 15 Pro"`) | +| `sub_model` | string? | System image variant for Android (e.g., `"Google API's"`, `"Google API's, Play Store"`) | +| `idiom` | string? | Form factor: `phone`, `tablet`, `watch`, `tv`, `desktop` | +| `platform_architecture` | string? | Raw platform ABI (e.g., `arm64-v8a`, `x86_64`, `arm64`) | +| `runtime_identifiers` | string[]? | .NET runtime identifiers | +| `architecture` | string? | Normalized CPU architecture (e.g., `arm64`, `x64`) | +| `is_emulator` | bool | True for emulator/simulator | +| `is_running` | bool | True if device is booted | +| `connection_type` | string? | `usb`, `wifi`, or `local` | +| `type` | string? | `Physical`, `Emulator`, or `Simulator` | +| `state` | string? | `Connected`, `Booted`, `Offline`, `Shutdown`, `Unknown` | +| `details` | object? | Additional platform-specific metadata (e.g., `tag_id`, `avd` for Android) | + +**Android-Specific Field Semantics**: + +| Field | Running Emulator | Shutdown Emulator | Physical Device | +|-------|-----------------|-------------------|-----------------| +| `identifier` | AVD name (e.g., `Pixel_8_API_35`) | AVD name | Serial (e.g., `R58M32XXXXX`) | +| `version` | API level from `ro.build.version.sdk` | API level from AVD config | API level from `ro.build.version.sdk` | +| `version_name` | `ro.build.version.release` | Mapped from API level | `ro.build.version.release` | +| `manufacturer` | `ro.product.manufacturer` | `"Google"` | `ro.product.manufacturer` | +| `platform_architecture` | Raw ABI (e.g., `arm64-v8a`) | From AVD config | Raw ABI from `ro.product.cpu.abi` | +| `sub_model` | Merged from AVD tag + `PlayStore.enabled` | From AVD tag + `PlayStore.enabled` | N/A | + +#### SdkPackage Schema + +```json +{ + "path": "platforms;android-35", + "version": "3", + "description": "Android SDK Platform 35", + "location": "/Users/dev/Library/Android/sdk/platforms/android-35", + "is_installed": true +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `path` | string | Package identifier (required) | +| `version` | string? | Installed/available version | +| `description` | string? | Human-readable description | +| `location` | string? | Install path (for installed packages) | +| `is_installed` | bool | True if currently installed | + +#### XcodeInstallation Schema + +```json +{ + "path": "/Applications/Xcode.app", + "developer_dir": "/Applications/Xcode.app/Contents/Developer", + "version": "16.2", + "build": "16C5032a", + "is_selected": true +} +``` + +| Field | Type | Description | +|-------|------|-------------| +| `path` | string | Path to Xcode.app bundle (required) | +| `developer_dir` | string | Path to Developer directory inside the bundle | +| `version` | string | Xcode version string | +| `build` | string | Xcode build number | +| `is_selected` | bool | True if this is the currently active Xcode (via `xcode-select`) | + +### 7.3 Capabilities Model + +| Command | Windows | macOS | OS Elevation | AI Agent Permission | +|---------|---------|-------|-------------|---------------------| +| `doctor` | ✓ | ✓ | No | None | +| `doctor --fix` | ✓ | ✓ | Sometimes* | `environment.modify` | +| `maui device list` | ✓ | ✓ | No | None | +| `maui device screenshot` | ✓ | ✓ | No | `device.capture` | +| `maui device logs` | ✓ | ✓ | No | `device.logs` | +| `maui android sdk list` | ✓ | ✓ | No | None | +| `maui android sdk install` | ✓ | ✓ | Sometimes* | `environment.modify` | +| `maui android sdk accept-licenses` | ✓ | ✓ | No | `environment.modify` | +| `maui android emulator create` | ✓ | ✓ | No | `device.create` | +| `maui android emulator start` | ✓ | ✓ | No | None | +| `maui android emulator stop` | ✓ | ✓ | No | None | +| `maui android emulator delete` | ✓ | ✓ | No | `device.create` | +| `maui android install` | ✓ | ✓ | Sometimes* | `environment.modify` | +| `maui android jdk check` | ✓ | ✓ | No | None | +| `maui android jdk install` | ✓ | ✓ | Sometimes* | `environment.modify` | +| `maui android jdk list` | ✓ | ✓ | No | None | +| `maui apple simulator list` | — | ✓ | No | None | +| `maui apple simulator start` | — | ✓ | No | None | +| `maui apple simulator stop` | — | ✓ | No | None | +| `maui apple simulator create` | — | ✓ | No | `device.create` | +| `maui apple simulator delete` | — | ✓ | No | `device.create` | +| `maui apple install` | — | ✓ | Sometimes* | `environment.modify` | +| `maui apple check` | — | ✓ | No | None | +| `maui apple runtime check` | — | ✓ | No | None | +| `maui apple runtime list` | — | ✓ | No | None | +| `maui apple runtime install` | — | ✓ | Yes (admin) | `environment.modify` | +| `maui apple xcode check` | — | ✓ | No | None | +| `maui apple xcode list` | — | ✓ | No | None | +| `maui apple xcode select` | — | ✓ | Yes (sudo) | `environment.modify` | +| `maui apple xcode accept-license` | — | ✓ | Yes (sudo) | `environment.modify` | + +*OS Elevation required for: installing Android SDK/JDK to system locations (e.g., `Program Files`), installing Xcode runtimes, switching Xcode, accepting Xcode licenses + +**AI Agent Permission Gates**: + +| Permission | Description | Default | +|------------|-------------|---------| +| None | Read-only operation — no approval required | Allow | +| `device.capture` | Capture screenshots or screen recordings | Prompt | +| `device.logs` | Stream device/simulator logs | Prompt | +| `device.create` | Create or delete emulators/simulators | Prompt | +| `environment.modify` | Install, update, or configure SDK/JDK/runtime components | Prompt | + + +--- + +## 8. User Experience + +### 8.1 IDE UI Flows + +> **See [IDE Integration](./maui-devtools-ide-integration.md)** for detailed VS Code status bars, environment panels, fix progress dialogs, and Visual Studio menu integration. + +### 8.2 Interactive Prompting + +When running in interactive mode (terminal), the tool prompts for missing information: + +**Example: Emulator Creation with Missing Parameters**: +``` +$ maui android emulator create + +? Emulator name: My_Pixel_5 + +? Select device profile: + ❯ Pixel 5 (1080x2340, 440dpi) + Pixel 6 (1080x2400, 411dpi) + Pixel 7 Pro (1440x3120, 512dpi) + (more...) + +? Select system image: + ❯ android-34 | Google APIs | x86_64 (recommended) + android-34 | Google Play | x86_64 + android-33 | Google APIs | x86_64 + (more...) + +Creating emulator 'My_Pixel_5'... done +``` + +**Non-Interactive Mode** (auto-detected in CI, or explicit `--interactive false`): +``` +$ maui android emulator create --interactive false +Error: --name is required in non-interactive mode (--interactive is false) +``` + +**Example: Large Download Confirmation**: +``` +$ maui doctor --fix + +The following will be installed: + • system-images;android-34;google_apis;x86_64 (2.6 GB) + • iOS 18.0 Runtime (8.1 GB) + +Total download size: 10.7 GB + +? Proceed? [Y/n] +``` + +### 8.3 Copilot-Assisted Troubleshooting + + +**Summary**: When automated fixes fail, the tool can escalate to GitHub Copilot with structured diagnostic context. The fallback hierarchy is: Automated Fix → Guided Manual Fix → Copilot-Assisted Troubleshooting → Community/Support Escalation. + +--- + +## 9. Diagnostics + +### 9.1 Redaction Rules + +All telemetry and logs follow these redaction rules: + +| Data Type | Rule | Example | +|-----------|------|---------| +| File paths | Replace with `` or keep structure | `/Users/name/code` → `/code` | +| Device names | Replace with type | `John's iPhone` → `` | +| Serial numbers | Redact | `R58M32XXXXX` → `` | +| Simulator IDs | Redact | `A1B2C3...` → `` | +| Error messages | Keep, unless contains path | Preserved | + +--- + + +## 10. MVP vs vNext Features + +### MVP (v1.0) + +| Priority | Feature | Status | +|----------|---------|--------| +| P0 | `doctor` command with status reporting | ✅ Implemented | +| P0 | `doctor --fix` for automated remediation | ✅ Implemented | +| P0 | Android SDK detection and installation | ✅ Implemented | +| P0 | Android emulator creation and management | ✅ Implemented | +| P0 | Android install (JDK + SDK from scratch) | ✅ Implemented | +| P0 | Android JDK management (check, install, list) | ✅ Implemented | +| P0 | Android SDK license acceptance | ✅ Implemented | +| P0 | iOS simulator listing and start/stop/create/delete | ✅ Implemented | +| P0 | iOS runtime listing | ✅ Implemented | +| P0 | Xcode installation listing and selection | ✅ Implemented | +| P0 | JSON output for all commands | ✅ Implemented | +| P0 | VS Code extension integration | ✅ In progress | +| P1 | Interactive prompting | Planned | + +### vNext (v1.x / v2.0) + +| Priority | Feature | +|----------|---------| +| P0 | Unified `device list` command (emulators, simulators, physical devices) | +| P0 | `device screenshot` command | +| P1 | Device log streaming | +| P1 | Visual Studio extension integration | +| P1 | iOS runtime installation guidance | +| P1 | `--correlation-id`, `--offline` global options | +| P2 | Emulator snapshot management | +| P2 | Windows SDK management | +| P2 | Linux host support (Android only) | +| P2 | Physical iOS device support (requires signing) | +| P2 | Telemetry (opt-in) | +| Future | MCP server integration for AI agents | +| Future | Cloud-hosted device support | + +--- + +## Related Documents + +| Document | Description | +|----------|-------------| +| [IDE Integration](./maui-devtools-ide-integration.md) | VS Code and Visual Studio UI flows | + +--- + +## Revision History + +| Version | Date | Changes | +|---------|------|---------| +| 2.16-draft | 2026-02-26 | Synced with merged summary spec (PR #34217): moved `device list`, `device screenshot`, `device logs` to vNext; updated IDE integration to reflect VS consuming `android-tools` NuGet directly; removed `runtime list --available` (no way to enumerate downloadable runtimes); replaced `maui doctor --json` IDE reference with specific check commands | +| 2.15-draft | 2026-02-26 | Changed default JDK version from 17 to 21 throughout; fixed `adb exec-out screencap` → `adb exec-out screencap -p` | +| 2.14-draft | 2026-02-25 | Restored `apple install` with `--accept-license` and `--runtime` flags (optionally accepts license, installs runtimes; could prompt for Xcode install in future); added `apple check` as read-only status; singular `accept-license` for Apple/Xcode matching `xcodebuild -license accept`; Android SDK keeps plural `accept-licenses` | +| 2.13-draft | 2026-02-19 | Expanded §6.8: added §6.8.1 Manifest-Driven Downloads & Checksum Verification — no hardcoded URLs, SHA-1 verification from Xamarin/Google manifest feeds. JDK install and SDK bootstrap planned for `dotnet/android-tools`. | +| 2.12-draft | 2026-02-19 | Added §6.8 Shared Libraries & Code Reuse — documents reuse of `Xamarin.Android.Tools.AndroidSdk` for SDK/JDK discovery and plan to contribute JDK installation, sdkmanager wrapper, license acceptance back to `dotnet/android-tools` | +| 2.10-draft | 2026-02-10 | Added `apple install` bootstrap command (Xcode + license + runtime), `runtime check`, `runtime list --available/--all`, `runtime install `, `xcode check`, `xcode accept-licenses`; changed `doctor --category` → `doctor --platform`; changed `emulator stop ` → `emulator stop ` for consistency | +| 2.9-draft | 2026-02-10 | Unified command naming: renamed `avd` → `emulator` for Android, `simulator boot` → `simulator start`, `simulator shutdown` → `simulator stop` for Apple — consistent start/stop verbs across platforms | +| 2.8-draft | 2026-02-09 | Synced with implementation: renamed `bootstrap` → `install` per PR feedback; removed `deploy`, `config`, `diagnostic-bundle` commands (covered by `dotnet run`/`dotnet build`); removed telemetry section (vNext); added Xcode list/select, XcodeInstallation schema, Android device field semantics, `type`/`state`/`details` to MauiDevice | +| 2.6-draft | 2026-02-04 | Condensed §3 Goals and §4 Personas into single section; Now 10 sections | +| 2.5-draft | 2026-02-04 | Removed §11 Security, §12 Extensibility; Added physical device support to device list | +| 2.4-draft | 2026-02-04 | Removed §13 Testing Strategy, §14 Rollout Plan | +| 2.3-draft | 2026-02-04 | Removed §15-20 (Open Questions, Appendix, Acceptance Criteria, etc.) | +| 2.2-draft | 2026-02-04 | Removed daemon mode, §5.7 Deploy vs Run, G6, NG6 | +| 2.1-draft | 2026-02-04 | Extracted AI/IDE integration to separate documents; Removed JSON-RPC API | +| 1.0-draft | 2026-02-03 | Initial draft | + +--- + +*End of Specification*