Files
wwtools/mxaccesscli
Joseph Doherty 7cbe2756d0 mxaccesscli: clean up diag output
Rewrites DiagCommand to match the structure of read/write/subscribe:

- Output goes through CliFx's IConsole instead of System.Console
  (kills the 6 CliFx_SystemConsoleShouldBeAvoided build warnings).
- Single concise summary line at the top: `diag <tag>  (<sec>s, <status>)`.
- Status now correctly distinguishes ok / error / no-events. A bogus
  reference produces a DataChange event with MxCategoryConfigurationError;
  that reports as "error", not the previous (incorrect) "ok".
- Adds --llm-json mode mirroring read/write: { query, ok, results: [...] }
  with register/add_item/events/totals fields.
- Captures both DataChange and OperationComplete events with status
  detail rendered consistently.
- Drops the duplicate "Done. Total events: N" / "diag result: events=N"
  trailing lines.

Also fixes exit-code propagation from soft-failure commands. Environment
.ExitCode set inside ExecuteAsync was being overwritten by CliFx's own
return from RunAsync. Program.Main now folds the two:

    return cliFxExit != 0 ? cliFxExit : Environment.ExitCode

This restores correct exit-on-failure behavior for both `diag` (error
status) and `write` (timeout / non-Ok ack) without resorting to
CommandException, which would print "ERROR\n<stack trace>" even for an
empty message.

Verified:
  diag TestChildObject.TestInt   -> EXIT 0, "ok"
  diag NoSuchObject.NoSuchAttr   -> EXIT 1, "error"
  diag --llm-json                -> structured envelope, ok flag honors statuses

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 20:19:40 -04:00
..

mxaccesscli

A .NET Framework 4.8 / x86 CliFx-based CLI for reading, writing, and subscribing to AVEVA System Platform tags via MxAccess (ArchestrA.MxAccess.LMXProxyServerClass). Output as scannable text or as a stable JSON envelope for LLM consumption. Built-in per-tag and per-call timeouts; structured surface of MxStatus categories on every error.

Hard constraints

  • MxAccess is a 32-bit COM proxy. The CLI must stay on net48 / x86 / [STAThread]. Do not retarget to .NET 10 or x64 — LMXProxyServerClass is registered for the WoW64 server only.
  • System Platform must be installed locally so that ArchestrA.MxAccess is registered with COM and the LMX runtime is reachable. Without it Register() fails with a COM error.
  • MxAccess events fire on the registering apartment. Calls must originate from an STA thread, which is why Program.Main is [STAThread]. If you call from a non-STA thread, events queue but never get pumped and your timeouts will always fire.
  • Reads are not synchronous in MxAccess. "Read" is implemented as a brief subscribe → wait for first OnDataChange → tear down. If a tag never delivers a DataChange (offscan, wrong reference, security denied), the read times out — that's the correct semantic, not a CLI bug.
  • Writes need user identity for secured attributes. Default --user-id 0 is "unauthenticated"; secured attributes will reject. Use --user-id <id> after calling AuthenticateUser() from another path (or, for a CLI smoke test, target a non-secured Writeable_USC_* attribute).

Layout

mxaccesscli/
  README.md                this file
  AGENTS.md                agent rules for working in this folder
  MxAccess.Cli.slnx
  lib/
    ArchestrA.MxAccess.dll (copied from System Platform's Framework\Bin)
  src/MxAccess.Cli/
    MxAccess.Cli.csproj
    Program.cs              [STAThread] entry point
    IsExternalInit.cs       net48 polyfill for C# 9 init accessors
    Commands/               read, write, subscribe, info
    Mx/                     MxSession, MxItem, MxUpdate, ValueCoercion
    Output/                 LLM-JSON envelope writer
  docs/
    usage.md                command surface, examples, JSON envelope contract
    api-notes.md            reverse-engineered MxAccess API reference (since AVEVA's
                            online docs are sparse): types, events, threading, status semantics

Resource index — by task

Task Go to
Agent rules for editing this CLI AGENTS.md
Run the CLI / option reference / examples docs/usage.md
MxAccess API surface, threading model, MxStatus semantics docs/api-notes.md
Find a writeable tag in the live galaxy (so smoke tests have a target) ../grdb/README.md
Read tag values via SQL retrieval (an alternative path) ../histdb/README.md

External documentation

AVEVA does not publish a single canonical MxAccess reference online. The closest official sources:

  • https://docs.aveva.com/ — search "MxAccess", "LMXProxyServer", "Object Viewer". Coverage is partial and depends on which product portal you land on.
  • AVEVA Knowledge Base (subscriber-only): TID-based articles on LMX registration, secured writes, and WriteSecured2.
  • The shipped MXAccess32.tlb type library at C:\Program Files (x86)\ArchestrA\Framework\Bin\ is the most authoritative source for method signatures. docs/api-notes.md summarizes what it exposes.

Build & run

dotnet build src/MxAccess.Cli/MxAccess.Cli.csproj -p:Platform=x86 -c Release

# Read two tags with a 3-second timeout, JSON envelope:
dotnet run --project src/MxAccess.Cli/MxAccess.Cli.csproj -- read TestMachine_001.Speed Reactor1.Level -t 3 --llm-json

# Write a value with explicit type:
dotnet run --project src/MxAccess.Cli/MxAccess.Cli.csproj -- write TestMachine_001.Setpoint 42.5 --type double

# Subscribe to a tag for 30 seconds, JSON Lines for streaming:
dotnet run --project src/MxAccess.Cli/MxAccess.Cli.csproj -- subscribe TestMachine_001.Speed -s 30 --llm-json

The built executable is bin\x86\Release\net48\mxa.exe. Drop on PATH and use mxa read ....

Maintenance

This README follows the doctrine in ../DOCS-GUIDE.md. When you add a command, an option, or a new field on the JSON envelope, update docs/usage.md in the same change. Update docs/api-notes.md only if the underlying MxAccess assembly changes (different System Platform version, etc.). The root ../CLAUDE.md carries one row pointing at this README — it should not need to change unless the tool's task surface changes.