Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions .claude/skills/maui-ai-debugging/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,73 @@ maui-devflow MAUI network --json | jq 'select(.statusCode >= 400)'
**WebSocket streaming:** The live monitor uses WebSocket (`/ws/network`) for real-time push.
Connecting clients receive a replay of buffered history, then live entries as they arrive.

### 8. App Storage (Preferences & Secure Storage)

Read, write, and delete app preferences and secure storage entries remotely. Useful for
debugging state, resetting app configuration, or injecting test values.

```bash
# Preferences (typed key-value store)
maui-devflow MAUI preferences list # list all known keys
maui-devflow MAUI preferences get theme_mode # get a string value
maui-devflow MAUI preferences get counter --type int # get a typed value
maui-devflow MAUI preferences set api_url "https://dev.example.com"
maui-devflow MAUI preferences set dark_mode true --type bool
maui-devflow MAUI preferences delete temp_key
maui-devflow MAUI preferences clear # clear all

# Shared preferences containers
maui-devflow MAUI preferences list --sharedName settings
maui-devflow MAUI preferences set key val --sharedName settings

# Secure Storage (encrypted, string values only)
maui-devflow MAUI secure-storage get auth_token
maui-devflow MAUI secure-storage set auth_token "eyJhbGc..."
maui-devflow MAUI secure-storage delete auth_token
maui-devflow MAUI secure-storage clear
```

**Note:** Preference key listing uses an internal registry (keys set via the agent are tracked).
Keys set directly in app code won't appear in `list` unless also set via the agent.

### 9. Platform Info & Device Features

Query read-only device and app state. These are one-shot snapshot reads.

```bash
maui-devflow MAUI platform app-info # app name, version, build, theme
maui-devflow MAUI platform device-info # manufacturer, model, OS, idiom
maui-devflow MAUI platform display # screen density, size, orientation
maui-devflow MAUI platform battery # charge level, state, power source
maui-devflow MAUI platform connectivity # WiFi/Cellular/Ethernet, network access
maui-devflow MAUI platform version-tracking # version history, first launch detection
maui-devflow MAUI platform permissions # check all common permission statuses
maui-devflow MAUI platform permissions camera # check a specific permission
maui-devflow MAUI platform geolocation # current GPS coordinates
maui-devflow MAUI platform geolocation --accuracy High --timeout 15
```

### 10. Device Sensors

Start, stop, and stream real-time sensor data. Sensors auto-start when streaming.

```bash
maui-devflow MAUI sensors list # list sensors + status
maui-devflow MAUI sensors start accelerometer # start a sensor
maui-devflow MAUI sensors stop accelerometer

# Stream readings to stdout (JSONL)
maui-devflow MAUI sensors stream accelerometer # Ctrl+C to stop
maui-devflow MAUI sensors stream gyroscope --speed Game # higher frequency
maui-devflow MAUI sensors stream compass --duration 10 # stop after 10 seconds
```

Available sensors: `accelerometer`, `barometer`, `compass`, `gyroscope`, `magnetometer`, `orientation`.
Speed options: `UI` (default), `Game`, `Fastest`, `Default`.

**WebSocket streaming:** Sensor data uses WebSocket (`/ws/sensors?sensor=<name>`) for
real-time push. Each reading is a JSON object with `sensor`, `timestamp`, and `data` fields.

## Command Reference

### maui-devflow MAUI (Native Agent)
Expand Down Expand Up @@ -340,6 +407,27 @@ resolution options are provided.
| `MAUI network list [--host H] [--method M]` | One-shot: dump recent captured HTTP requests |
| `MAUI network detail <requestId>` | Full request/response details: headers, body, timing |
| `MAUI network clear` | Clear the captured request buffer |
| `MAUI preferences list [--sharedName N]` | List all known preference keys and values |
| `MAUI preferences get <key> [--type T] [--sharedName N]` | Get a preference value. Types: string, int, bool, double, float, long, datetime |
| `MAUI preferences set <key> <value> [--type T] [--sharedName N]` | Set a preference value |
| `MAUI preferences delete <key> [--sharedName N]` | Remove a preference |
| `MAUI preferences clear [--sharedName N]` | Clear all preferences |
| `MAUI secure-storage get <key>` | Get a secure storage value |
| `MAUI secure-storage set <key> <value>` | Set a secure storage value |
| `MAUI secure-storage delete <key>` | Remove a secure storage entry |
| `MAUI secure-storage clear` | Clear all secure storage entries |
| `MAUI platform app-info` | App name, version, build, package, theme |
| `MAUI platform device-info` | Device manufacturer, model, OS, idiom |
| `MAUI platform display` | Screen density, size, orientation, refresh rate |
| `MAUI platform battery` | Battery level, state, power source |
| `MAUI platform connectivity` | Network access and connection profiles |
| `MAUI platform version-tracking` | Current/previous/first version, build history, isFirstLaunch |
| `MAUI platform permissions [name]` | Check permission status. Omit name to check all common permissions |
| `MAUI platform geolocation [--accuracy A] [--timeout N]` | Get current GPS coordinates. Accuracy: Lowest, Low, Medium (default), High, Best |
| `MAUI sensors list` | List available sensors and their current state (started/stopped) |
| `MAUI sensors start <sensor> [--speed S]` | Start a sensor. Sensors: accelerometer, barometer, compass, gyroscope, magnetometer, orientation. Speed: UI (default), Game, Fastest, Default |
| `MAUI sensors stop <sensor>` | Stop a sensor |
| `MAUI sensors stream <sensor> [--speed S] [--duration N]` | Stream sensor readings via WebSocket. Duration 0 = indefinite (Ctrl+C to stop) |
| `commands [--json]` | List all available commands with descriptions. `--json` returns machine-readable schema with command names, descriptions, and whether they mutate state |

Element IDs come from `MAUI tree` or `MAUI query`. AutomationId-based elements use their
Expand Down
12 changes: 11 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Agent architecture:
```

- **Single port** (default 9223, configurable via `.mauidevflow` file) serves both native MAUI commands, CDP, and WebSocket connections
- **WebSocket support** — `/ws/network` streams captured HTTP requests in real-time; CDP still uses HTTP POST via Chobitsu
- **WebSocket support** — `/ws/network` streams captured HTTP requests in real-time; `/ws/logs` streams log entries; `/ws/sensors?sensor=<name>` streams device sensor readings; CDP still uses HTTP POST via Chobitsu
- **Multi-WebView CDP** — Each `BlazorWebView` registers independently with the agent. CDP commands accept `?webview=<id>` to target by index, AutomationId, or element ID. The `BlazorWebViewDebugServiceBase` manages per-WebView state via inner `WebViewBridge` instances
- **Blazor→Agent wiring** uses reflection to avoid a direct package dependency between the two NuGet packages

Expand Down Expand Up @@ -112,6 +112,16 @@ The CLI command `maui-devflow update-skill` downloads the latest skill files fro
- **CLI**: `MAUI network` (live TUI), `MAUI network --json` (JSONL streaming), `MAUI network list`, `MAUI network detail`, `MAUI network clear`
- **Apple namespace conflict**: Agent.Core's `Network` namespace conflicts with Apple's `Network` framework — use fully-qualified `MauiDevFlow.Agent.Core.Network.DevFlowHttpHandler` in AgentServiceExtensions.cs

## Platform Features (Preferences, SecureStorage, Device Info, Sensors)

- **Preferences CRUD**: `/api/preferences` endpoints for list/get/set/delete/clear. MAUI's `Preferences` API has no "list all" method — the agent tracks known keys via an internal registry key (`__devflow_known_keys`) stored as a unit-separator-delimited string. Only keys set via the agent are tracked.
- **SecureStorage CRUD**: `/api/secure-storage` endpoints for get/set/delete/clear via `SecureStorage` static API.
- **Platform Info**: Read-only endpoints under `/api/platform/` for app-info, device-info, device-display, battery, connectivity, version-tracking, permissions, geolocation. All use MAUI's static API classes (`AppInfo.Current`, `DeviceInfo.Current`, `DeviceDisplay.MainDisplayInfo`, `Battery.Default`, `Connectivity.Current`, `VersionTracking.Default`, `Geolocation.GetLocationAsync()`).
- **Permissions**: The agent maintains a `KnownPermissions` dictionary mapping friendly names to `Permissions.BasePermission` factories. Check one or all permissions via `/api/platform/permissions[/{name}]`.
- **Sensor Streaming**: `SensorManager` class manages sensor lifecycle (start/stop) and WebSocket broadcasting. Supports: accelerometer, barometer, compass, gyroscope, magnetometer, orientation. WebSocket at `/ws/sensors?sensor=<name>` auto-starts the sensor on connect and broadcasts JSON readings to all subscribers. REST endpoints for list/start/stop at `/api/sensors`.
- **DELETE routes**: `AgentHttpServer` supports DELETE method via `_deleteRoutes` dictionary and `MapDelete()`, used by preferences and secure-storage delete endpoints.
- **CLI**: `MAUI preferences`, `MAUI secure-storage`, `MAUI platform`, `MAUI sensors` command groups with full subcommands.

## Windows Support

- **Agent**: Reports `platform: "WinUI"`, `idiom: "Desktop"`. Startup uses `OnActivated` lifecycle event because `Application.Current` is not available during `OnLaunched`.
Expand Down
41 changes: 41 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ manually check the simulator.
- **Blazor WebView Debugging** — CDP bridge using Chobitsu for JavaScript evaluation, DOM manipulation, page navigation. Supports multiple BlazorWebViews per app with independent targeting
- **Unified Logging** — Native `ILogger` and WebView `console.log/warn/error` unified into a single log stream with source filtering
- **Network Request Monitoring** — Automatic HTTP traffic interception via DelegatingHandler with real-time WebSocket streaming, body capture, and JSONL output
- **App Storage Management** — Read, write, and delete Preferences (typed key-value) and SecureStorage entries remotely
- **Platform Features** — Query device info, battery, connectivity, display, permissions, version tracking, geolocation, and app info
- **Sensor Streaming** — Start/stop device sensors (accelerometer, gyroscope, compass, barometer, magnetometer, orientation) with real-time WebSocket streaming
- **Broker Daemon** — Automatic port assignment and agent discovery for simultaneous multi-app debugging
- **CLI Tool** (`maui-devflow`) — Scriptable commands for both native and Blazor automation
- **Driver Library** — Platform-aware (Mac Catalyst, Android, iOS Simulator, Linux/GTK) orchestration
Expand Down Expand Up @@ -172,6 +175,22 @@ maui-devflow MAUI network list # one-shot dump of recent requests
maui-devflow MAUI network detail <id> # full headers + body for a request
maui-devflow MAUI network clear # clear captured requests

# App storage
maui-devflow MAUI preferences list # list known keys
maui-devflow MAUI preferences get theme_mode # get a value
maui-devflow MAUI preferences set api_url "https://dev.example.com"
maui-devflow MAUI secure-storage get auth_token # encrypted storage

# Platform info & sensors
maui-devflow MAUI platform app-info # app name, version, theme
maui-devflow MAUI platform device-info # manufacturer, model, OS
maui-devflow MAUI platform battery # charge level, state
maui-devflow MAUI platform connectivity # network access, profiles
maui-devflow MAUI platform permissions # check all permission statuses
maui-devflow MAUI platform geolocation # GPS coordinates
maui-devflow MAUI sensors list # list sensors + status
maui-devflow MAUI sensors stream accelerometer # live WebSocket stream

# Live edit native properties (no rebuild)
maui-devflow MAUI set-property HeaderLabel TextColor "Tomato"
maui-devflow MAUI set-property HeaderLabel FontSize "32"
Expand Down Expand Up @@ -281,6 +300,28 @@ auto-assigned by the broker (range 10223–10899), or configurable via `.mauidev
| `/api/network/{id}` | GET | Full request/response details (headers, body) |
| `/api/network/clear` | POST | Clear captured request buffer |
| `/ws/network` | WS | WebSocket stream of HTTP requests (replay + live) |
| `/api/preferences` | GET | List all known preference keys and values. `?sharedName=N` for shared container |
| `/api/preferences/{key}` | GET | Get preference value. `?type=int\|bool\|double\|...` `?sharedName=N` |
| `/api/preferences/{key}` | POST | Set preference `{"value":"...","type":"string","sharedName":null}` |
| `/api/preferences/{key}` | DELETE | Remove a preference key |
| `/api/preferences/clear` | POST | Clear all preferences (optionally `?sharedName=N`) |
| `/api/secure-storage/{key}` | GET | Get secure storage value |
| `/api/secure-storage/{key}` | POST | Set secure storage `{"value":"..."}` |
| `/api/secure-storage/{key}` | DELETE | Remove secure storage entry |
| `/api/secure-storage/clear` | POST | Clear all secure storage entries |
| `/api/platform/app-info` | GET | App name, version, build, theme, layout direction |
| `/api/platform/device-info` | GET | Manufacturer, model, platform, idiom, OS version |
| `/api/platform/device-display` | GET | Screen width, height, density, orientation, refresh rate |
| `/api/platform/battery` | GET | Charge level, state, power source, energy saver status |
| `/api/platform/connectivity` | GET | Network access level and connection profiles |
| `/api/platform/version-tracking` | GET | Version/build history, first launch info |
| `/api/platform/permissions` | GET | Check status of all known permissions |
| `/api/platform/permissions/{name}` | GET | Check a specific permission status |
| `/api/platform/geolocation` | GET | GPS coordinates. `?accuracy=Medium` `?timeout=10` |
| `/api/sensors` | GET | List all sensors with support/active/subscriber status |
| `/api/sensors/{sensor}/start` | POST | Start sensor. `?speed=UI\|Game\|Fastest\|Default` |
| `/api/sensors/{sensor}/stop` | POST | Stop sensor |
| `/ws/sensors` | WS | Stream sensor readings. `?sensor=accelerometer` `?speed=UI` |
| `/api/cdp` | POST | Forward CDP command to Blazor WebView. Use `?webview=<id>` to target a specific WebView |
| `/api/cdp/webviews` | GET | List registered CDP WebViews (index, AutomationId, elementId, ready status) |
| `/api/cdp/source` | GET | Get page HTML source. Use `?webview=<id>` to target a specific WebView |
Expand Down
8 changes: 7 additions & 1 deletion src/MauiDevFlow.Agent.Core/AgentHttpServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class AgentHttpServer : IDisposable
private readonly int _port;
private readonly Dictionary<string, Func<HttpRequest, Task<HttpResponse>>> _getRoutes = new();
private readonly Dictionary<string, Func<HttpRequest, Task<HttpResponse>>> _postRoutes = new();
private readonly Dictionary<string, Func<HttpRequest, Task<HttpResponse>>> _deleteRoutes = new();
private readonly Dictionary<string, Func<TcpClient, NetworkStream, HttpRequest, CancellationToken, Task>> _wsRoutes = new();

public int Port => _port;
Expand All @@ -35,6 +36,9 @@ public void MapGet(string path, Func<HttpRequest, Task<HttpResponse>> handler)
public void MapPost(string path, Func<HttpRequest, Task<HttpResponse>> handler)
=> _postRoutes[path.TrimEnd('/')] = handler;

public void MapDelete(string path, Func<HttpRequest, Task<HttpResponse>> handler)
=> _deleteRoutes[path.TrimEnd('/')] = handler;

public void MapWebSocket(string path, Func<TcpClient, NetworkStream, HttpRequest, CancellationToken, Task> handler)
=> _wsRoutes[path.TrimEnd('/')] = handler;

Expand Down Expand Up @@ -223,7 +227,9 @@ private async Task HandleClientAsync(TcpClient client, CancellationToken ct)

private async Task<HttpResponse> RouteRequestAsync(HttpRequest request)
{
var routes = request.Method.Equals("POST", StringComparison.OrdinalIgnoreCase) ? _postRoutes : _getRoutes;
var routes = request.Method.Equals("POST", StringComparison.OrdinalIgnoreCase) ? _postRoutes
: request.Method.Equals("DELETE", StringComparison.OrdinalIgnoreCase) ? _deleteRoutes
: _getRoutes;

// Try exact match first
if (routes.TryGetValue(request.Path, out var handler))
Expand Down
Loading
Loading