# Native TestClient command shell

The `test-client` binary is a native Rust multi-client shell. It does not load
the former C# executable or start a CLR process. The command registry owns the
implemented system, communication, inventory, appearance, asset, movement,
object, parcel, estate, grid, agent, friends, groups, directory, statistics,
and voice-capability commands. `pending_test_client_commands()` is empty, and
the completeness audit compares the source, generated, implementation, and
runtime registries.

## Social, directory, and statistics behavior

Directory searches use native correlated, paged result streams and retain the
upstream 20-second response bound. Group cache, member, and role requests are
correlated with their native events and preserve the upstream timeouts. Friend
mapping, UUID/name resolution, event details, and group operations propagate
shell cancellation.

`who` maintains a live coarse-location roster and resolves display names;
`bots` also tracks source UUIDs from decoded viewer-effect packets. Profile
cloning combines the AgentProfile capability with the matching legacy interests
reply to replace profile text, images, URL, interests, and picks before joining
and activating the target's public groups. `play list` exposes all 135 built-in
animations from the pinned source catalog and also accepts arbitrary animation
asset UUIDs. Statistics come from each simulator's thread-safe native counters.
Directory and collection results are bounded at 65,535 entries.

## World command behavior

Movement commands use `AgentManager` movement updates, autopilot, teleport,
sit, stand, flight, and home APIs. Timed movement is limited to 60 seconds and
checks cancellation while sending updates. `follow` retains the selected
avatar and refreshes autopilot whenever a coarse-location update moves it;
`follow off` cancels autopilot. Region crossing is bounded to 60 seconds.

Object queries snapshot the current simulator caches before filtering.
Searches and parcel/map results are capped at 65,535 entries. Linkset export
requires ownership, sorts serialized LLSD deterministically, limits a linkset
to 10,000 primitives, and downloads each unique texture as both JPEG 2000 and
TGA. Import accepts only a bounded LLSD array, waits for each native rez event,
applies primitive properties, links children, and restores root rotation and
permissions. Individual asset and terrain files are limited to 64 MiB. Regular
expressions are limited in source and compiled size.

`textures on` downloads the textures already visible in the current simulator
and subscribes newly observed primitives for deduplicated native asset-cache
requests. `--gettextures` enables that subscription at login. Parcel, grid,
wind, owner, selection, covenant, and terrain commands use their corresponding
native managers and propagate cancellation through request/reply waits.

## Live-operation gates

Read-only queries need no privilege flag. Every movement, teleport, derez,
permission, import, tree, and terrain mutation requires both
`--allow-live-mutations` at process startup and `--confirm` on the command.
Import and terrain upload additionally require `--allow-spending`; estate
terrain download/upload additionally require `--allow-estate-actions`.
Consequently the default invocation cannot move an avatar, alter or create an
object, upload an asset, or invoke an estate-owner action.

Profile cloning, generic messages, animation starts, touches, group activation,
invitations, joins, and leaves use the same two-part mutation gate. Read-only
friend, group, directory, region, uptime, dilation, and statistics commands do
not require a gate. Profile cloning and direct group joins additionally require
`--allow-spending`, because an open group can charge an enrollment fee and the
client cannot safely infer that fee before every UUID-based join.

Output paths reject parent-directory traversal. Timeouts, cancellation, file
limits, result limits, and linkset limits apply equally to live and fake-grid
runs. Passwords and login secrets continue to pass through the shell's common
redaction path.

## Offline verification

Fake scripts can seed the same command layer with `!world-region`,
`!world-avatar`, `!world-prim`, `!world-parcel`, `!world-parcel-owner`,
`!world-parcel-object`, `!world-grid-region`, `!world-layer`,
`!world-agent-location`, `!world-estate`, `!world-asset`, and `!world-syntax`
tab-separated directives. These fixtures never open a network connection.

The service layer additionally accepts `!service-avatar`, `!service-friend`,
`!service-group`, `!service-group-result`, `!service-group-member`,
`!service-group-role`, `!service-person`, `!service-classified`,
`!service-event`, `!service-event-info`, `!service-land`, `!service-place`,
`!service-sim`, `!service-animation`, and `!service-utilization[-row]` fixtures.

Run the issue-focused compatibility gate with:

```text
cargo test -p libremetaverse-programs --test test_client_world_cli
cargo test -p libremetaverse-programs --test test_client_services_cli
```

The world gate drives every command owned by the movement/object/land/grid
issue, checks the exact fake backend calls, round-trips a linkset through
import, and validates generated assets. The services gate drives every
remaining service and voice-capability command in a single offline session,
verifies the destructive-operation guards, proves voice account values stay
redacted, and proves the pending inventory is empty.
