Initial commit: Wonderware / System Platform tools and reference

Five tools under one repo, all docs organized per DOCS-GUIDE.md:

- aalogcli: .NET 4.8 / x86 CliFx CLI for reading System Platform binary
  logs (*.aaLGX) for LLM debugging, built on aaOpenSource/aaLog. Commands:
  last, tail, range, unread, fields. Stable JSON envelope under --llm-json.
  Build template under lib/build/ for rebuilding aaLogReader.dll.

- aot: ArchestrA Object Toolkit 2014 v4.0 reference material. Dev guide
  (Markdown converted from CHM), API reference for the ArchestrA.Toolkit
  namespace, and the Monitor / Watchdog VS sample solutions.

- graccesscli: .NET 4.8 / x86 CliFx CLI that automates Galaxy
  configuration via the ArchestrA GRAccess COM interop. Includes session
  daemon, IPC protocol, and llm-json envelope contract.

- grdb: SQL/DDL exploration of the Galaxy Repository database. DDL
  captures, reusable queries, hierarchy / contained-name <-> tag-name
  translation notes.

- histdb: LLM-oriented reference for AVEVA Historian retrieval. INSQL
  linked-server, extension tables, every wwXxx time-domain extension,
  every retrieval mode, alarm/event SQL recipes, REST API. Distilled
  from the 243-page Historian Retrieval Guide.

Root contains:
- CLAUDE.md: thin index pointing into each tool's README.
- DOCS-GUIDE.md: doctrine for organizing docs for LLM consumption.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-03 18:22:20 -04:00
commit 32f26272ae
411 changed files with 69973 additions and 0 deletions
+245
View File
@@ -0,0 +1,245 @@
# CliFx Reference (v2.3.6)
Local reference for the CliFx CLI framework. Source: https://github.com/Tyrrrz/CliFx
## Setup
```csharp
using CliFx;
public static class Program
{
public static async Task<int> Main() =>
await new CliApplicationBuilder()
.AddCommandsFromThisAssembly()
.Build()
.RunAsync();
}
```
**Important:** `Main()` must return the integer exit code from `RunAsync()`.
`RunAsync()` resolves args from `Environment.GetCommandLineArgs()` and env vars from `Environment.GetEnvironmentVariables()`. You can also provide them manually via overloads.
## Defining Commands
Commands implement `ICommand` and are decorated with `[Command]`:
```csharp
using CliFx;
using CliFx.Attributes;
[Command(Description = "Calculates the logarithm of a value.")]
public class LogCommand : ICommand
{
[CommandParameter(0, Description = "Value whose logarithm is to be found.")]
public required double Value { get; init; }
[CommandOption("base", 'b', Description = "Logarithm base.")]
public double Base { get; init; } = 10;
public ValueTask ExecuteAsync(IConsole console)
{
var result = Math.Log(Value, Base);
console.Output.WriteLine(result);
return default;
}
}
```
Use `IConsole` (not `System.Console`) for all console I/O — this enables testability.
## Parameters vs Options
| Aspect | `[CommandParameter]` | `[CommandOption]` |
|---|---|---|
| Binding | By position order | By name (`--foo`) or short name (`-f`) |
| Required by default | Yes | No |
| Make optional | Omit `required` (last param only) | Omit `required` |
| Make required | Use `required` keyword | Use `required` keyword |
| Non-scalar (collections) | Only last parameter | Any option |
| Env var fallback | No | Yes (`EnvironmentVariable = "ENV_FOO"`) |
```csharp
// Required option
[CommandOption("foo")]
public required string Foo { get; init; }
// Optional parameter (must be last)
[CommandParameter(0)]
public string? OptionalParam { get; init; }
// Option with env var fallback
[CommandOption("foo", EnvironmentVariable = "ENV_FOO")]
public required string FooWithFallback { get; init; }
// Non-scalar option
[CommandOption("items")]
public required IReadOnlyList<string> Items { get; init; }
```
## Argument Syntax (POSIX-style)
```
myapp [...directives] [command] [...parameters] [...options]
```
- `--foo bar` → option "foo" = "bar"
- `-f bar` → option 'f' = "bar"
- `--switch` → option "switch" (no value / boolean)
- `-abc` → options 'a', 'b', 'c' (no value)
- `-i file1.txt file2.txt` → option 'i' = ["file1.txt", "file2.txt"]
- `-i file1.txt -i file2.txt` → same as above
## Value Conversion
Supports out of the box:
- **Primitives**: `int`, `bool`, `double`, `ulong`, `char`, etc.
- **Date/time**: `DateTime`, `DateTimeOffset`, `TimeSpan`
- **Enums**: by name or numeric value
- **String-initializable**: types with `ctor(string)` or static `Parse(string)` — e.g. `FileInfo`, `Guid`, `BigInteger`
- **Nullable** versions of all above
- **Collections**: `T[]`, `IReadOnlyList<T>`, `List<T>`, `HashSet<T>`, etc.
### Custom Converter
```csharp
public class VectorConverter : BindingConverter<Vector2>
{
public override Vector2 Convert(string? rawValue)
{
if (string.IsNullOrWhiteSpace(rawValue))
return default;
var components = rawValue.Split('x', 'X', ';');
var x = int.Parse(components[0], CultureInfo.InvariantCulture);
var y = int.Parse(components[1], CultureInfo.InvariantCulture);
return new Vector2(x, y);
}
}
[CommandParameter(0, Converter = typeof(VectorConverter))]
public required Vector2 Point { get; init; }
```
## Multiple / Nested Commands
Give each command a unique name. Common name segments create hierarchy:
```csharp
[Command] // Default (unnamed) command
public class DefaultCommand : ICommand { ... }
[Command("cmd1")] // Child of default
public class FirstCommand : ICommand { ... }
[Command("cmd1 sub")] // Child of cmd1
public class SubCommand : ICommand { ... }
```
Usage: `myapp cmd1 sub arg1 --opt value`
Default command is optional. If absent, running without a command shows root help text.
## Error Reporting
Use `CommandException` to report errors with specific exit codes:
```csharp
throw new CommandException("Division by zero is not supported.", 133);
```
Exit codes should be 1255 (8-bit unsigned) to avoid overflow on Unix.
## Graceful Cancellation
```csharp
public async ValueTask ExecuteAsync(IConsole console)
{
var cancellation = console.RegisterCancellationHandler();
await DoSomethingAsync(cancellation);
}
```
First interrupt signal triggers the token. Second interrupt force-kills.
## Dependency Injection
Use `UseTypeActivator(...)` with `Microsoft.Extensions.DependencyInjection`:
```csharp
await new CliApplicationBuilder()
.AddCommandsFromThisAssembly()
.UseTypeActivator(commandTypes =>
{
var services = new ServiceCollection();
services.AddSingleton<MyService>();
foreach (var commandType in commandTypes)
services.AddTransient(commandType);
return services.BuildServiceProvider();
})
.Build()
.RunAsync();
```
## Testing
Use `FakeInMemoryConsole` to test commands in isolation:
### Command-level test
```csharp
using var console = new FakeInMemoryConsole();
var command = new ConcatCommand { Left = "foo", Right = "bar" };
await command.ExecuteAsync(console);
var stdOut = console.ReadOutputString();
Assert.Equal("foo bar", stdOut);
```
### Application-level test
```csharp
using var console = new FakeInMemoryConsole();
var app = new CliApplicationBuilder()
.AddCommand<ConcatCommand>()
.UseConsole(console)
.Build();
var args = new[] { "--left", "foo", "--right", "bar" };
var envVars = new Dictionary<string, string>();
await app.RunAsync(args, envVars);
var stdOut = console.ReadOutputString();
Assert.Equal("foo bar", stdOut);
```
## Debug & Preview Directives
```bash
# Suspend until debugger attaches
myapp [debug] cmd -o
# Print parsed args without executing
myapp [preview] cmd arg1 -o foo
```
Disable in production:
```csharp
new CliApplicationBuilder()
.AllowDebugMode(false)
.AllowPreviewMode(false)
.Build();
```
## .NET Framework 4.8 Notes
- CliFx targets .NET Standard 2.0+, fully compatible with net48
- `required` keyword requires C# 11+ — on net48 (LangVersion 9.0), use properties with default values and validate in `ExecuteAsync` instead
- `init` setters require C# 9+ (supported on net48 with LangVersion 9.0)
- `async Task<int> Main` requires `System.Threading.Tasks` using directive on net48