An open API service indexing awesome lists of open source software.

https://github.com/wieslawsoltes/inspector

Inspector is a .NET CLI and runtime infrastructure for inspecting and manipulating Avalonia UI trees.
https://github.com/wieslawsoltes/inspector

avalonia avaloniaui cli coding-agents inspector logical-tree visual-tree

Last synced: about 2 months ago
JSON representation

Inspector is a .NET CLI and runtime infrastructure for inspecting and manipulating Avalonia UI trees.

Awesome Lists containing this project

README

          

# Inspector

[![CI](https://github.com/wieslawsoltes/Inspector/actions/workflows/ci.yml/badge.svg)](https://github.com/wieslawsoltes/Inspector/actions/workflows/ci.yml)
[![Release](https://github.com/wieslawsoltes/Inspector/actions/workflows/release.yml/badge.svg)](https://github.com/wieslawsoltes/Inspector/actions/workflows/release.yml)

Inspector is a .NET CLI and runtime infrastructure for inspecting and manipulating Avalonia UI trees.
It is designed for both human use and coding-agent automation with deterministic, machine-readable output.

## What it does

- Enumerates **visual** and **logical** trees
- Reads node property metadata and values
- Applies node/property mutations (set property, insert/remove/move/reparent)
- Exposes capabilities and stable schema metadata for automation
- Supports:
- **Host mode** (instrumented runtime in app)
- **Process mode** (CLI-side no-host attach via `--pid` or `--name`)

## NuGet packages

| Package | Version | Downloads | Install |
| --- | --- | --- | --- |
| [`Inspector.Contracts`](https://www.nuget.org/packages/Inspector.Contracts) | [![NuGet](https://img.shields.io/nuget/v/Inspector.Contracts?logo=nuget)](https://www.nuget.org/packages/Inspector.Contracts) | [![NuGet](https://img.shields.io/nuget/dt/Inspector.Contracts?logo=nuget)](https://www.nuget.org/packages/Inspector.Contracts) | `dotnet add package Inspector.Contracts` |
| [`Inspector.Transport`](https://www.nuget.org/packages/Inspector.Transport) | [![NuGet](https://img.shields.io/nuget/v/Inspector.Transport?logo=nuget)](https://www.nuget.org/packages/Inspector.Transport) | [![NuGet](https://img.shields.io/nuget/dt/Inspector.Transport?logo=nuget)](https://www.nuget.org/packages/Inspector.Transport) | `dotnet add package Inspector.Transport` |
| [`Inspector.Host`](https://www.nuget.org/packages/Inspector.Host) | [![NuGet](https://img.shields.io/nuget/v/Inspector.Host?logo=nuget)](https://www.nuget.org/packages/Inspector.Host) | [![NuGet](https://img.shields.io/nuget/dt/Inspector.Host?logo=nuget)](https://www.nuget.org/packages/Inspector.Host) | `dotnet add package Inspector.Host` |
| [`Inspector.AvaloniaAdapter`](https://www.nuget.org/packages/Inspector.AvaloniaAdapter) | [![NuGet](https://img.shields.io/nuget/v/Inspector.AvaloniaAdapter?logo=nuget)](https://www.nuget.org/packages/Inspector.AvaloniaAdapter) | [![NuGet](https://img.shields.io/nuget/dt/Inspector.AvaloniaAdapter?logo=nuget)](https://www.nuget.org/packages/Inspector.AvaloniaAdapter) | `dotnet add package Inspector.AvaloniaAdapter` |
| [`Inspector.Cli.Tool`](https://www.nuget.org/packages/Inspector.Cli.Tool) | [![NuGet](https://img.shields.io/nuget/v/Inspector.Cli.Tool?logo=nuget)](https://www.nuget.org/packages/Inspector.Cli.Tool) | [![NuGet](https://img.shields.io/nuget/dt/Inspector.Cli.Tool?logo=nuget)](https://www.nuget.org/packages/Inspector.Cli.Tool) | `dotnet tool install --global Inspector.Cli.Tool` |

## Installation

### Library packages

Install the package you need:

```bash
dotnet add package Inspector.Contracts
dotnet add package Inspector.Transport
dotnet add package Inspector.Host
dotnet add package Inspector.AvaloniaAdapter
```

### CLI as .NET tool

Global tool:

```bash
dotnet tool install --global Inspector.Cli.Tool
inspector --help
```

Local tool manifest:

```bash
dotnet new tool-manifest
dotnet tool install --local Inspector.Cli.Tool
dotnet tool run inspector --help
```

Update/uninstall:

```bash
dotnet tool update --global Inspector.Cli.Tool
dotnet tool uninstall --global Inspector.Cli.Tool
```

## Repository layout

```text
src/
Inspector.Contracts Shared DTOs/enums/schema contracts
Inspector.Transport Local transport/session/authorization model
Inspector.Host In-process host runtime abstractions
Inspector.AvaloniaAdapter Tree/property/mutation adapter implementations
Inspector.Cli Command-line interface and agent-friendly output
tests/
Inspector.Tests xUnit test suite
samples/
Inspector.SampleApp Minimal host runtime integration sample
```

## Requirements

- .NET SDK compatible with `net10.0`

## CI build and release scripts

- `scripts/ci-build.sh`: restore, build, test, and pack all publishable packages.
- `scripts/ci-release.sh`: runs `ci-build.sh` and pushes `.nupkg`/`.snupkg` to NuGet.
- `.github/workflows/ci.yml`: PR/push validation + package artifact upload.
- `.github/workflows/release.yml`: tag/manual release publishing to NuGet (`NUGET_API_KEY` secret required).

Run locally:

```bash
bash scripts/ci-build.sh
```

Release locally:

```bash
NUGET_API_KEY= VERSION=0.1.0 bash scripts/ci-release.sh
```

## CLI help (latest)

```text
Inspector.Cli command surface
Usage:
inspector capabilities
inspector connect [--mode ] [--address ] [--pid ] [--name ] [--client-id ] [--client-version ] [--secret ] [--scope ]...
inspector tree get --session-id [--kind visual|logical]
inspector node get-properties --session-id --node-id
inspector node set-property --session-id --node-id --property --value [--operation-id ]
inspector tree mutate --session-id --target-node-id --operation [--payload ] [--dry-run] [--operation-id ]
inspector tree batch-mutate --session-id --operations [--dry-run] [--operation-id ]
Global options:
--json Emit deterministic JSON output
--output Select output mode
--help, -h Show help
Exit codes: 0=success, 2=validation error, 3=execution error, 10=unexpected error
```

## CLI usage examples

```bash
# Capabilities
inspector capabilities --json

# Connect (host mode)
inspector connect --mode host --address local://inspector --client-id my-tool --json

# Connect (process mode by pid)
inspector connect --mode process --pid 12345 --json

# Connect (process mode by name)
inspector connect --mode process --name Inspector.SampleApp --json

# Visual tree
inspector tree get --session-id sess-123 --kind visual --json

# Node properties
inspector node get-properties --session-id sess-123 --node-id visual-button --json

# Set property
inspector node set-property --session-id sess-123 --node-id visual-button --property Width --value 320 --json

# Mutate tree (dry-run)
inspector tree mutate --session-id sess-123 --target-node-id visual-button --operation move --payload '{"index":0}' --dry-run --json

# Batch mutate (single call, multiple operations)
inspector tree batch-mutate --session-id sess-123 --operations '[{"targetNodeId":"visual-label","operation":"set-property","payload":{"property":"Text","value":"Welcome back"}},{"targetNodeId":"visual-root","operation":"insert","payload":{"typeName":"TextBox","name":"EmailInput","properties":{"Watermark":"Email"}}}]' --json
```

If you are developing from source, you can run the same commands with:

```bash
dotnet run --project src/Inspector.Cli -- [args]
```

### Host mode full tree mutability payloads

When connected with `--mode host`, `tree mutate` supports structural and property mutations with JSON payloads:

- `set-property`: `{"property":"","value":}`
- `insert`: `{"typeName":"","nodeId":"","name":"","classes":["..."],"properties":{"...":...},"index":0}`
- `move`: `{"index":1}`
- `reparent`: `{"parentNodeId":"","index":0}`
- `remove`: payload optional

The same operation payloads are also used by `tree batch-mutate` entries.

Examples:

```bash
# Create a new control node under visual-root (nodeId can be omitted for auto-generation)
inspector tree mutate --session-id --target-node-id visual-root --operation insert --payload '{"typeName":"Avalonia.Controls.TextBox","name":"EmailInput","properties":{"Text":"","Watermark":"Email"}}' --json

# Set any property via tree mutate payload
inspector tree mutate --session-id --target-node-id visual-label --operation set-property --payload '{"property":"Text","value":"Ready to login"}' --json

# Reparent and remove
inspector tree mutate --session-id --target-node-id child-node --operation reparent --payload '{"parentNodeId":"new-parent","index":0}' --json
inspector tree mutate --session-id --target-node-id old-node --operation remove --json

# Batch mutate using either raw array or { "operations": [...] }
inspector tree batch-mutate --session-id --operations '{"operations":[{"targetNodeId":"visual-label","operation":"set-property","payload":{"property":"Text","value":"Ready to login"}},{"targetNodeId":"visual-root","operation":"insert","payload":{"typeName":"Avalonia.Controls.TextBox","name":"EmailInput","properties":{"Watermark":"Email"}}}]}' --json
```

## Process mode guide (`--mode process`)

Use this mode to target an already-running process by PID or process name.

1) Connect and capture session id:

```bash
inspector connect --mode process --pid --json
# or
inspector connect --mode process --name --json
```

Check `data.processSnapshotAvailable` in connect output:
- `true`: live UI snapshot is available
- `false`: CLI will use fallback process metadata

2) Reuse returned `sessionId` in follow-up commands:

```bash
inspector tree get --session-id --kind visual --json
inspector node get-properties --session-id --node-id --json
inspector node set-property --session-id --node-id --property --value --json
```

For apps that include the sample snapshot publisher integration:
- `node set-property` queues live property mutation commands for the running process.
- `tree mutate` in process mode also queues live structural mutation commands (`insert`, `remove`, `move`, `reparent`, `set-property`) so runtime controls can be added/rearranged without restarting the app.
- `tree batch-mutate` applies multiple mutations in one CLI call and queues each live process mutation command in order for faster bulk updates.

3) Common process-mode errors:
- `cli.process.not_found`: PID/name not found
- `cli.process.ambiguous`: multiple processes match `--name` (retry with `--pid`)
- `cli.process.exited`: process ended before command execution

When the target app publishes live inspector snapshots (the included `Inspector.SampleApp` does), process mode returns live visual/logical nodes and node properties instead of fallback process metadata.
If no live snapshot is published by the target process, process mode falls back to process metadata nodes.

## Session model

- `connect` creates a session and returns `sessionId`.
- Session state is persisted across CLI invocations in a local temporary session store.
- `tree get`, `node get-properties`, `node set-property`, `tree mutate`, and `tree batch-mutate` require a valid `--session-id`.

## Output behavior

- Defaults to **JSON** when input/output is redirected (non-interactive)
- Supports explicit output selection via `--output text|json`
- `--json` forces deterministic JSON output
- Errors are returned with explicit non-zero exit codes

## Agent skill integration (Codex)

Repository includes a single Codex skill definition:

- `SKILL/inspector-avalonia-cli/SKILL.md`

Install it locally:

```bash
mkdir -p ~/.codex/skills/inspector-avalonia-cli
cp SKILL/inspector-avalonia-cli/SKILL.md ~/.codex/skills/inspector-avalonia-cli/SKILL.md
```

## Sample app

`samples/Inspector.SampleApp` is an Avalonia desktop app (`dotnet` Avalonia template) with inspector host wiring via `InspectorHostRuntime` and `DelegateInspectorRequestHandler`.

Run it with:

```bash
dotnet run --project samples/Inspector.SampleApp
```

Then connect from CLI in host mode:

```bash
inspector connect --mode host --address local://inspector --json
```

## Current implementation status

This repository includes a functioning foundation (contracts, transport model, host runtime, adapter services, CLI, tests, sample app), including process-mode connection via `--pid`/`--name` and session-aware CLI workflows.