Eternet.Agents.Control.Cli
2.0.28
Prefix Reserved
dotnet tool install --global Eternet.Agents.Control.Cli --version 2.0.28
dotnet new tool-manifest
dotnet tool install --local Eternet.Agents.Control.Cli --version 2.0.28
#tool dotnet:?package=Eternet.Agents.Control.Cli&version=2.0.28
nuke :add-package Eternet.Agents.Control.Cli --version 2.0.28
Eternet.Agents.Control.Cli
Eternet.Agents.Control.Cli installs the eac command, a deterministic local harness for Eternet repositories. It gives humans and agents a versioned way to discover capabilities, load implementation guidance, collect fresh diagnostics, plan remediation, apply bounded fixes, inspect mediator pipelines, call internal services, manage plugins, and verify work.
The CLI is intentionally discovery-first. Agents should not load every artifact into context. They should ask EAC for the current surface, page into the data they need, and reuse persisted run IDs instead of recomputing evidence.
Install
dotnet tool install --global Eternet.Agents.Control.Cli
Install or update a pinned version:
dotnet tool install --global Eternet.Agents.Control.Cli --version <version>
dotnet tool update --global Eternet.Agents.Control.Cli --version <version>
eac --version
When dogfooding unreleased changes from this repository, build Release and prefer the repo-local CLI command so the captured evidence matches current source instead of a potentially older global tool install:
dotnet run --project src\Eternet.Agents.Control.Cli\Eternet.Agents.Control.Cli.csproj -c Release --no-build -- --version
dotnet run --project src\Eternet.Agents.Control.Cli\Eternet.Agents.Control.Cli.csproj -c Release --no-build -- capabilities list --format json
Use the repo-local command as the default fallback while the global tool is stale or the global tool store is locked. The repo-local DLL remains a valid lower-level fallback when you specifically need to invoke the built output directly.
For local dogfood from this checkout, pack and install a timestamped tool build:
$version = "2.0.0-local.$(Get-Date -Format 'yyyyMMdd.HHmmss')"
dotnet pack src\Eternet.Agents.Control.Cli\Eternet.Agents.Control.Cli.csproj -c Release -o artifacts\nupkg /p:Version=$version /p:PackageVersion=$version
dotnet tool update --global Eternet.Agents.Control.Cli --add-source artifacts\nupkg --version $version --ignore-failed-sources
eac --version
Do not add --no-build when packing a new local tool version. A stale Release build can keep the previous
AssemblyInformationalVersion, which makes eac --version look older even when the NuGet package version changed.
Package Source Mapping For Local Tool Packages
If local dogfood uses unpublished packages and NuGet.Config enables package source mapping, do not rely on
--add-source alone. Use a temporary config that maps the EAC package family to the local feed and leaves nuget.org as
the fallback for transitive dependencies. dotnet tool rejects combining --add-source with package source mapping, so
the temporary config must carry the local feed entry by itself.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="local-eac" value="D:\src\Chat\.eac-local-feed" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="local-eac">
<package pattern="Eternet.Agents.Control.Cli" />
<package pattern="Eternet.Agents.Control.*" />
</packageSource>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
</packageSourceMapping>
</configuration>
Then point the tool install or update at that config instead of editing the repo-owned NuGet.Config:
dotnet tool update --global Eternet.Agents.Control.Cli `
--configfile D:\temp\eac-tool.NuGet.Config `
--version $version `
--ignore-failed-sources
Use --tool-path <temp-dir> for disposable local smoke when you want the same package-resolution proof without mutating the
real global tool store.
Locked Global Tool Store
dotnet tool update --global can fail if another shell, editor, or long-running process still has eac loaded from the
global tool store. A foreground eac plan run host can hold that lock until the command exits. When that happens:
- Close processes that are still running
eacor holding the tool files open. - Retry the same
dotnet tool update --global ...command once. - If the machine still blocks the global store, keep verification on the current checkout with the repo-local CLI command until the store lock is cleared.
dotnet run --project src\Eternet.Agents.Control.Cli\Eternet.Agents.Control.Cli.csproj -c Release --no-build -- --version
dotnet run --project src\Eternet.Agents.Control.Cli\Eternet.Agents.Control.Cli.csproj -c Release --no-build -- capabilities list --format json
If dotnet run --project ... --no-build -- is not available, direct DLL verification is the lower-level fallback. Both
paths keep rollout validation on the current source tree instead of waiting for a workstation-specific tool-store issue.
Architecture
flowchart LR
User["Human or agent"] --> CLI["eac CLI"]
CLI --> Discovery["Capabilities and guidance"]
CLI --> Evidence["Diagnostics and verification"]
CLI --> Planning["Remediation, cleanup, plan folders"]
CLI --> Domain["Mediator, templates, legacy DB, services"]
CLI --> Plugins["Plugin runtime"]
Discovery --> Core["Eternet.Agents.Control.Core"]
Evidence --> Core
Planning --> Core
Domain --> Core
Plugins --> Core
Core --> Workspace["Target workspace"]
Core --> Artifacts[".eac/artifacts"]
Core --> Analyzers["Transient analyzers"]
Core --> ServiceCatalog["Internal HTTP services"]
Core --> PluginStores["Repo/global plugin stores"]
Core owns orchestration, safety, artifact persistence, transient analyzer injection, plugin loading, and stable JSON contracts. Plugins own optional diagnostics, analyzer assemblies, code fixes, transformers, and domain migrations. The plugin migration backlog is tracked in docs/PLUGINS_TODO.md.
Progressive Disclosure
Use broad discovery commands first, search before loading authored guidance or wide plugin datasets, then narrow requests
with IDs, run IDs, pages, and detail flags. Core commands reuse the common disclosure vocabulary: --detail summary for
counts and next-step hints, --detail page --skip <n> --take <n> for bounded rows or sections, and --detail full for
the richest projection of the current bounded page. full never means "dump every matching item inline."
Queryable plugin commands use the dataset engine with --dataset, --select, --filter, --orderby, --skip, and
--top; plugin authors should prefer that dataset contract for heavy row-oriented outputs instead of returning large
nested payloads.
Choose the contract that matches the shape of the output:
| Contract | Use when | Query / paging vocabulary | Default and follow-up behavior |
|---|---|---|---|
| Disclosure | The command returns one nested object or mixed graph and callers need summary/page/full projections. | --detail summary|page|full, --skip, --take |
Keep the default compact; use --detail full only when the current bounded page needs the richest projection. |
| Dataset | The command returns row-oriented inventory, findings, logs, events, or other tabular results that benefit from projection, filtering, ordering, paging, and persisted reuse. | --dataset, --select, --filter, --orderby, --skip, --top, --persist-result, --result-id |
Keep the default dataset preview bounded; let callers ask for more rows or a persisted result explicitly. |
| List | The command already returns a small flat list and does not need nested disclosure or dataset semantics. | --skip, --take |
Keep list paging separate from dataset --top. |
| Guidance | The command returns authored knowledge, not operational data. | guidance search, guidance toc, guidance show --detail summary|page|full, --search, --skip, --take |
Search first, then load one bounded page of matching sections. Legacy --full remains a compatibility alias for the same bounded --detail full behavior. |
Every partial response should surface enough follow-up data to continue safely instead of forcing the caller to guess:
pageInfo for counts/cursors, budgetInfo and partialInfo for truncation reason, next/previous/search commands when
available, and artifact references when the full payload is only safe out of band.
Default response budgets come from ADR 0002 and stay physically enforced even after semantic normalization:
| Response budget | Default page | Full-page ceiling | Hard max |
|---|---|---|---|
| Serialized response chars | 30,000 | 60,000 | 120,000 |
| Serialized response UTF-8 bytes | 64 KiB | 128 KiB | 256 KiB |
If a command misses semantic paging, the final writer guardrail returns a compact fallback envelope rather than leaking the raw oversized payload. That fallback keeps the command name, observed size, and any continuation, search, or artifact hints needed to fetch more safely.
Guidance Section Model
Guidance packs now publish stable authored sections instead of one synthetic full blob. Start with
guidance search --query <text> when you know the concept but not the pack id, then use guidance toc --id <pack> to
inspect section ids, titles, and tags before loading content. guidance show --id <pack> returns the pack's
compact/default sections, guidance show --sections <id> and guidance show --tags <tag> load authored slices
intentionally, and guidance show --detail full returns all matching sections for the current bounded page. Legacy
guidance show --full is still accepted, but it maps to the same bounded full-detail page behavior and does not bypass
budgets.
Release-oriented packs can expose larger non-compact sections, such as rollout guidance, without forcing those sections into the compact default output that agents load by default.
Consumer Migration Notes
When updating existing scripts, docs, or agent prompts for the economy model:
- Treat compact output as the default contract. If a command used to return the full graph by default, request
--detail fullexplicitly or move to--detail pagewhen a bounded slice is enough. - For guidance, switch from loading whole packs up front to
guidance search, thenguidance toc, thenguidance show --detail page ...orguidance show --detail full ...for the current bounded page. - For queryable plugin output, stop parsing plugin-specific
payload.resultJsonblobs or legacy paging flags and use the host-owned dataset query and cache options instead.
flowchart TD
Start["Start task"] --> Cap["eac capabilities --format json"]
Cap --> CapList["capabilities list"]
CapList --> CapShow["capabilities show --id <id>"]
Cap --> GuidanceList["guidance list"]
GuidanceList --> Families["guidance families"]
Families --> Family["guidance family --id <family>"]
GuidanceList --> GuidanceSearch["guidance search --query <text>"]
GuidanceSearch --> Toc["guidance toc --id <pack>"]
Toc --> Sections["guidance show --id <pack> --detail page"]
Sections --> Work["Run focused evidence command"]
Diagnostics use the same model:
sequenceDiagram
participant A as Agent
participant E as eac
participant W as Workspace
participant F as .eac artifacts
A->>E: diagnose all --workspace <repo> --format json
E->>W: inject transient analyzers and build
E->>F: persist result.json and logs
E-->>A: compact manifest with runId and grouped counts
A->>E: diagnose list --from-run <runId> --source eac --diagnostic <id>
E-->>A: one page of findings
A->>E: diagnose show --from-run <runId> --item eac:0
E-->>A: one focused diagnostic with properties
Capability Map
flowchart TB
EAC["eac"]
EAC --> Discover["Discovery<br/>capabilities, guidance"]
EAC --> Diagnose["Evidence<br/>diagnose, tooling, verify"]
EAC --> Remediate["Remediation<br/>status, waves, code fixes"]
EAC --> Cleanup["Cleanup impact<br/>inventory, reachability, cleanup"]
EAC --> Mediator["Mediator<br/>inventory, inspect, graph, validate, compare"]
EAC --> Plans["Plan folders<br/>inspect, scaffold, runbook, workflow, guard, run"]
EAC --> Plugins["Plugins<br/>inspect, install, list, uninstall"]
EAC --> Services["Services<br/>auth, catalog, invoke"]
EAC --> Templates["Templates<br/>list, show, install, update, create"]
EAC --> Legacy["Legacy DB<br/>snapshots and testing assets"]
EAC --> AI["Read-only AI<br/>reason"]
Command Surface
| Area | Commands | Purpose |
|---|---|---|
| Discovery | capabilities, capabilities list, capabilities show |
Discover the installed EAC command and guidance contract. |
| Guidance | guidance list, guidance search, guidance show, guidance toc, guidance suggest, guidance families, guidance family |
Search and load versioned guidance progressively instead of relying on stale prompt memory. |
| Diagnostics | diagnose, diagnose all, diagnose ingest, diagnose list, diagnose show |
Produce or inspect normalized analyzer evidence. |
| Tooling | tooling inspect, tooling update |
Check, update, and bootstrap diagnostic package declarations that affect evidence completeness. |
| Remediation | remediation plan, remediation status, remediation waves, remediation code-fixes, remediation apply-codefix |
Convert stored diagnostics into recipes, waves, and bounded deterministic fixes. |
| Verification | verify |
Re-check current worktree evidence and optionally run build/test commands. |
| Cleanup | inventory collect, reachability analyze, cleanup plan, cleanup explain, cleanup diff, cleanup verify |
Analyze deletion/trim impact from persisted inventory, explicit specs, and git diff evidence. |
| Mediator | mediator inventory, mediator inspect, mediator graph, mediator validate, mediator compare |
Inspect mediator pipeline facts, quality signals, graphs, and persisted snapshots. |
| Review | review pr |
Create artifact-first PR review contracts by dispatching the Core review command and emitting contract/lineage/runtime artifacts. |
| Plan folders | plan inspect, plan scaffold, plan runbook, plan workflow, plan guard, plan run |
Standardize repo-local plan execution and guard checks. |
| Plugins | plugins inspect, plugins install, plugins list, plugins uninstall |
Discover, install, and run EAC plugin packages. |
| Templates | templates list, templates show, templates install, templates update, templates create |
Discover and instantiate allowlisted Eternet .NET templates. |
| Services | services list, services show, services operations, services operation, services schemas, services operation-schema, services health, services invoke |
Discover and call allowlisted internal HTTP services through OpenAPI metadata. |
| Auth | auth login, auth status, auth logout, auth token list, auth token revoke, auth approval request, auth approval status, auth approval cancel |
Store and manage server tokens plus supervisor approval lifecycle used by service calls. |
| Legacy DB | legacy-db snapshots status, versions, show, download, create; legacy-db testing scaffold, refresh, inspect |
Manage legacy DB metadata snapshots and repo-local testing assets. |
| AI | ai reason |
Ask Copilot or Codex for read-only reasoning. Not a source of deterministic evidence. |
Review Contracts
review pr is artifact-first by default and dispatches the Core ExecutePullRequestReviewCommand
boundary. The CLI accepts a full Core request/configuration file through --config, overlays explicit
flags, then emits a contract JSON plus companion markdown/lineage/runtime metadata artifacts when
--emit is provided.
eac review pr --workspace <repo> --pull-request-url https://github.com/org/repo/pull/42 --backend copilot --model gpt-5.4 --publish-canonical-comment false --publish-inline-comments false --emit .eac/review/review-pr-contract.json --format json
For local dogfood, --workspace can infer owner/repo from the GitHub origin remote, so the PR
number is enough:
eac review pr 42 --workspace <repo> --emit .eac/review/pr-42 --format json
For remote-only artifact runs, a full pull request URL can be supplied without a workspace:
eac review pr https://github.com/org/repo/pull/42 --emit .eac/review/pr-42 --format json
Use repeatable --step-override values to control individual lanes:
eac review pr --config review-config.json --step-override concurrency:selectionMode=run,agent=codex,model=gpt-5.4,timeoutSeconds=900 --step-override relationalFramework:selectionMode=skip,enabled=false
Safe dogfood runs should keep publication disabled with --publish-canonical-comment false and
--publish-inline-comments false. --canonical-publication-mode accepts per-execution, rolling,
or per-revision; disabling publication is controlled by the publication flags, not by a none mode.
Discovery And Guidance
Start every agent workflow by discovering the installed contract:
eac capabilities --format json
eac capabilities list --format json
eac guidance list --format json
eac guidance search --query mediator --format json
eac guidance families --format json
Then load only the relevant detail:
eac capabilities show --id remediation-waves --format json
eac guidance toc --id mediator --format json
eac guidance show --id mediator --detail page --take 1 --format text
eac guidance show --id mediator --sections quick-start,decision-tree --detail full --format text
eac guidance suggest --diagnostic EAR001 --format json
Current guidance domains include agent workflow, cleanup impact, templates, plan folders, review dogfood hardening, services, legacy DB testing, mediator implementation, mediator testing, mediator contracts, relational CRUD, naming, REST endpoints, legacy entities, Firebird, Blazor testing, and EternetDataGrid.
Profile-Aware Capability Listing
Capability discovery supports profile-aware authorization and local-safety projection:
# Allowed capabilities only (default projection)
eac capabilities list --format json
# Include denied capabilities with denial reason tokens
eac capabilities list --include-denied --format json
# Project current-user capability profile summary
eac capabilities profile --format json
When denied capabilities are included, each item can project denialReason values such as authzDenied,
localSafetyDenied, authMissing, authExpired, and authUnavailable so automation can branch without parsing prose.
When canRequestSupervisorApproval is true, denial messages include request and retry guidance.
Plugin Capabilities
Plugin capabilities are generated from validated executable CLI command leaves, not from manifest tags. Every plugin command that has an OperationId or DiagnosticId generates a corresponding agent-facing capability.
Authoritative Source
Executable capabilities come exclusively from EacPluginCliCommand leaves after alias and scope resolution:
# List all host and built-in capabilities (no workspace required)
eac capabilities list --format json
# List built-in plugin capabilities only
eac capabilities list --plugin built-in --format json
# List capabilities from a specific plugin by alias (requires workspace for repo/global plugins)
eac capabilities list --plugin sf --workspace <repo> --format json
# Show detailed capability information (workspace required for plugin capabilities)
eac capabilities show --id plugin-sf-inventory --workspace <repo> --format json
Important: Plugin capabilities are inaccessible without --workspace context. Use --workspace <repo> to resolve repo-scoped or global plugin capabilities.
Manifest Capabilities vs Executable Commands
Manifest.Capabilities is non-authoritative for agent command discovery. Manifest tags are catalog metadata only:
- Manifest.Capabilities: Freeform package tags for discovery, review, and human-facing categorization (not validated).
- Cli.Commands leaves: Executable command paths with validated intent, options, output contract, and apply support (authoritative).
Agents must use capabilities list and capabilities show to discover executable plugin capabilities, not parse manifest tags. See ADR 0003 for details.
Structured Capability Fields
Starting with contract version 2.1, CommandCapability exposes typed fields for agent-driven filtering:
{
"id": "plugin-sf-inventory",
"name": "sf inventory",
"description": "Query Service Fabric nodes and services",
"agentDefault": false,
"producesFreshEvidence": true,
"stableJsonOutput": true,
"workspaceMode": "optional",
"supportsApply": false,
"hasQueryableOutput": true,
"defaultDatasetId": "live-nodes",
"operationId": "service-fabric-inventory",
"diagnosticId": null,
"pluginScope": "repo",
"pluginPackageId": "EAC.Plugin.Extension.ServiceFabric",
"pluginVersion": "0.1.0",
"aliasSource": "eac sf",
"pluginPermissions": ["github:repo"],
"relatedGuidanceIds": ["sf-cluster-health", "sf-node-remediation"],
"constraints": ["Requires Service Fabric cluster connection"],
"samples": [...]
}
These fields enable agents to filter by workspace mode, apply support, queryable output, operation/diagnostic IDs, plugin scope, and permissions without parsing prose description.
Backward Compatibility: Existing consumers that ignore structured fields continue to work. Prose fields (Description, Constraints, Samples) remain for human readability and backward compatibility.
Additive Capability Enrichment
Optional plugin metadata (EacPluginCliCapability) enriches generated capabilities without duplicating the executable contract:
- Does NOT override: command path, intent, options, output contracts, apply support.
- Does enrich: agent defaults, fresh-evidence signals, category tags, guidance links, safety notes, example invocations.
See ADR 0002 and ADR 0004 for details.
Diagnostics
diagnose generates fresh evidence by building the workspace with transient analyzer injection. The stdout JSON is a compact manifest; the full run is persisted under .eac/artifacts/diagnose/<run-id>/.
eac diagnose --workspace <repo> --format json
eac diagnose all --workspace <repo> --target src/App.slnx --format json
eac diagnose all --workspace <repo> --diff HEAD --format json
eac diagnose --workspace <repo> --changed-files src/Foo.cs,src/Bar.cs --format json
Use stored-run paging instead of loading result.json into context:
eac diagnose list --workspace <repo> --from-run <run-id> --source eac --diagnostic EANC001 --skip 0 --take 50 --format json
eac diagnose show --workspace <repo> --from-run <run-id> --item eac:0 --format json
eac diagnose list --workspace <repo> --from-run <run-id> --source external --diagnostic CS8602 --take 25 --format json
diagnose ingest exists for compatibility and debugging existing SARIF. Use fresh diagnose or verify for agent verification.
Tooling Health
Some diagnostics depend on Eternet runtime and generator/analyzer package declarations in the target repo.
eac tooling inspect --workspace <repo> --profile mediator --format json
eac tooling update --workspace <repo> --profile mediator --format json
eac tooling update --workspace <repo> --profile mediator --apply --format json
Run tooling update without --apply first. It can update stale versions and add missing package declarations. After
applying package updates, run fresh diagnostics again.
Remediation
Remediation is run-ID based. First collect evidence, then plan/status/waves from that same run.
flowchart LR
Diagnose["diagnose all"] --> RunId["runId"]
RunId --> Status["remediation status"]
RunId --> Plan["remediation plan --diagnostic <id>"]
RunId --> Waves["remediation waves --emit-plan"]
RunId --> DryRun["remediation apply-codefix"]
DryRun --> Apply["remediation apply-codefix --apply"]
Apply --> Verify["verify"]
Common commands:
eac remediation status --workspace <repo> --from-run <run-id> --format json
eac remediation plan --workspace <repo> --diagnostic EAR001 --from-run <run-id> --format json
eac remediation waves --workspace <repo> --from-run <run-id> --emit-plan .eac/remediation/waves.md --format json
eac remediation code-fixes --format json
eac remediation apply-codefix --workspace <repo> --from-run <run-id> --diagnostic EM018 --format json
eac remediation apply-codefix --workspace <repo> --from-run <run-id> --diagnostic EM018 --apply --format json
Do not run broad dotnet format analyzers commands by hand for EAC remediation. EAC owns explicit target files, batch sizes, safety metadata, dry-run/apply separation, and postflight expectations.
Analyzer Plugin Stack
The first-party analyzer rollout is package-based:
EAC.Plugin.AnalyzerCatalogis the built-in catalog plugin boundary.- The family packages own the analyzer DLLs and any package-owned
codeFixMetadataineac-plugin.json. remediation code-fixesreportssourcePackagefrom the owning family package manifest, not from legacyEternet.Analyzers.
Current built-in family packages are:
EAC.Plugin.NamingEAC.Plugin.FeatureFolderEAC.Plugin.LocalizationEAC.Plugin.ContractsEAC.Plugin.ODataEAC.Plugin.MediatorEAC.Plugin.Mediator
When dogfooding unpublished analyzer packages, pack them to a local feed, set EAC_ANALYZER_PACKAGE_SOURCES, and point restore at a config that maps EAC.Plugin.AnalyzerCatalog* to that feed when NuGet.Config uses package source mapping. This keeps diagnose and code-fix execution on the normal NuGet/MSBuild path instead of a custom loader.
To add a future analyzer package, ship the analyzer DLLs and optional codeFixMetadata in the owning family package, update the built-in catalog plugin only if the package should load by default, and extend the dogfood/test feed recipe so the new package can be restored before publication.
Verification
eac verify --workspace <repo> --target <change-name> --format json
eac verify --workspace <repo> --target <change-name> --build-target src/App.slnx --format json
eac verify --workspace <repo> --target <change-name> --tests "dotnet test tests/App.Tests/App.Tests.csproj -c Release --no-restore" --format json
Analyzer/build evidence is the default verification path. Tests are opt-in because they can be expensive or domain-specific.
Cleanup Impact Analysis
Cleanup work uses persisted inventory plus an explicit cleanup spec.
flowchart TD
Inventory["inventory collect"] --> Reachability["reachability analyze --from-inventory"]
Reachability --> Explain["cleanup explain"]
Reachability --> Plan["cleanup plan"]
Plan --> Edits["Manual or agent cleanup edits"]
Edits --> Diff["cleanup diff --baseline"]
Diff --> Verify["cleanup verify"]
Commands:
eac inventory collect --workspace <repo> --target src/App.slnx --profile source,blazor,aspnet,mediator --include src,tests --exclude docs --format json
eac reachability analyze --workspace <repo> --from-inventory <run-id> --spec cleanup-spec.json --format json
eac cleanup explain --workspace <repo> --from-run <run-id> --file src/Legacy/Foo.cs --format json
eac cleanup plan --workspace <repo> --from-run <run-id> --detail summary --format json
eac cleanup plan --workspace <repo> --from-run <run-id> --detail full --emit-plan .eac/cleanup/waves.md --format json
eac cleanup diff --workspace <repo> --baseline main --head HEAD --format json
eac cleanup verify --workspace <repo> --spec cleanup-spec.json --from-run <run-id> --include src,tests --exclude docs --format json
Use the same include/exclude scope for inventory and verification when docs, plans, samples, or archived code are not part
of the product surface. Use cleanup diff after edits to quantify added, modified, and deleted files by cleanup bucket,
deleted .cs test files by tests/<project>, and removed [Fact]/[Theory] attributes. Treat uncertain dynamic usage
as blocked, not deletable.
Mediator Inspection
Mediator commands expose pipeline inventory without forcing the agent to infer everything from source text.
eac mediator inventory --workspace <repo> --tier catalog --page-size 5 --format json
eac mediator inventory --workspace <repo> --pipeline EnrichIssueOnDemand --tier outline --format json
eac mediator inventory --workspace <repo> --pipeline ReasonWithAi --tier full --format json
eac mediator inspect --workspace <repo> --symbol EnrichIssueOnDemand --detail summary --format json
eac mediator inspect --workspace <repo> --file src/App/Features/Orders/ExecuteOrder.cs --detail full --format json
eac mediator graph --workspace <repo> --symbol ReasonWithAi --graph-format mermaid --format json
eac mediator validate --workspace <repo> --pipeline ReasonWithAi --format json
eac mediator compare --workspace <repo> --baseline baseline.json --current current.json --format json
Inventory output is tiered:
catalog: one row per pipeline, capped for discovery.outline: ordered steps and key risk signals.full: step contracts, graph, diagnostics, recipes, and quality findings.
Large workspaces should use --tier, --page, --page-size, --limit, --pipeline, --diff, --changed-files, or --from-run to keep output bounded.
<details> <summary>Example: catalog page from this repo</summary>
Command:
eac mediator inventory --workspace D:/src/Chat/Eternet.Agents.Control --tier catalog --page-size 5 --format json
Trimmed output:
{
"version": "2.0",
"tier": "catalog",
"pageInfo": {
"page": 1,
"pageSize": 5,
"totalCount": 229,
"hasNextPage": true,
"cursor": "ListAuthTokens"
},
"catalog": [
{
"name": "ReasonWithAi",
"kind": "execute",
"stepCount": 1,
"branchCount": 0,
"isStateful": false,
"hasRetry": false,
"file": "src/Eternet.Agents.Control.Cli/Commands/Ai/ReasonWithAi/ReasonWithAi.cs",
"line": 28,
"diagnosticCount": 2
}
]
}
</details>
<details> <summary>Example: outline for a Web enrichment pipeline</summary>
Command:
eac mediator inventory --workspace D:/src/Chat/Eternet.Agents.Control --pipeline EnrichIssueOnDemand --tier outline --format json
Trimmed output:
{
"version": "2.0",
"tier": "outline",
"pageInfo": {
"totalCount": 1,
"hasNextPage": false
},
"outlines": [
{
"name": "EnrichIssueOnDemand",
"kind": "execute",
"file": "src/Eternet.Agents.Control.Web/Features/Enrichment/EnrichIssue/EnrichIssueOnDemand.cs",
"requestType": "EnrichIssueOnDemand.Request",
"responseType": "EnrichIssueOnDemand.Response",
"steps": [
{ "order": 1, "name": "GetIssueWithRepositoryAsync", "isAsync": true },
{ "order": 7, "name": "BuildEnrichmentInventoryAsync", "hasEfWrite": true, "isAsync": true },
{ "order": 15, "name": "PersistEnrichmentResultAsync", "hasEfWrite": true, "isAsync": true },
{ "order": 18, "name": "FinalizeEnrichIssueResult", "isAsync": false }
],
"saveChangesCount": 1,
"writeUnitCount": 5,
"isStateful": false,
"hasRetry": false,
"diagnosticIds": ["EANM011", "EAR001"]
}
]
}
</details>
<details> <summary>Example: graph output for a small CLI pipeline</summary>
Command:
eac mediator graph --workspace D:/src/Chat/Eternet.Agents.Control --symbol ReasonWithAi --graph-format mermaid --format json
Trimmed output:
{
"graphFormat": "mermaid",
"graph": {
"summary": {
"pipelineCount": 1,
"nodeCount": 2,
"edgeCount": 1
}
},
"source": {
"primary": "sourceScan"
},
"text": "flowchart TD\n pipeline_ReasonWithAi[\"ReasonWithAi\"]\n step_ExecuteReasoningAsync[\"ExecuteReasoningAsync\"]\n pipeline_ReasonWithAi -->|starts-with| step_ExecuteReasoningAsync"
}
Rendered:
flowchart TD
pipeline_ReasonWithAi["ReasonWithAi"]
step_ExecuteReasoningAsync["ExecuteReasoningAsync"]
pipeline_ReasonWithAi -->|starts-with| step_ExecuteReasoningAsync
</details>
Plan Folders
EAC can scaffold and inspect repo-local plan folders, identify the next wave, generate runbooks, run configured guards, and optionally run the implementer pass.
In this repository, those plan-folder operations are owned by the built-in EAC.Plugin.Plans plugin. The CLI host keeps
PlanCommandModule only as a compatibility adapter so the public eac plan command names, JSON shape, and streamed-run
behavior stay stable while plan ownership remains plugin-backed.
Current dogfood still shows that the compatibility adapter does not expose the plugin dataset query flags on the root
eac plan surface, so --dataset, --select, --filter, --orderby, --skip, --top, and --count remain follow-up
work even though the underlying plan plugin metadata advertises queryable output.
Until that host parity lands, treat root eac plan automation as bounded default output plus explicit runbook/workflow
follow-ups; do not script dataset query flags against the compatibility adapter yet.
eac plan scaffold --workspace <repo> --name billing-migration --title "Billing Migration" --format json
eac plan scaffold --workspace <repo> --name billing-migration --title "Billing Migration" --apply --format json
eac plan inspect --workspace <repo> --plan-folder plans/billing-migration --format json
eac plan runbook --workspace <repo> --plan-folder plans/billing-migration --format json
eac plan workflow --workspace <repo> --plan-folder plans/billing-migration --format json
eac plan guard --workspace <repo> --plan-folder plans/billing-migration --format json
eac plan run --workspace <repo> --plan-folder plans/billing-migration --print-only --format json
eac plan run --workspace <repo> --plan-folder plans/billing-migration --format json
Use plan runbook when another runner should execute the wave. Backend, model, and reasoning normally resolve from local-wave-stack.settings.json; --backend, --model, and --reasoning-effort are temporary overrides and should be recorded in the active wave when used. Run plan run as a foreground, blocking command; do not start it in the background and poll PIDs, logs, or activity artifacts. plan run owns backend waiting, mirrors child-agent output to stderr, and preserves the final structured result on stdout. Use plan guard to validate plan rules without running an agent CLI.
Dogfood Evidence
Plan folders can also carry replayable evidence summaries for closeout gates:
eac plan evidence extract-rollout --workspace <repo> --plan-folder plans/<plan> --rollout-log <jsonl> --source-id CHAT-1381 --output reports/chat-1381-summary.json --format json
eac plan evidence import-github --workspace <repo> --plan-folder plans/<plan> --fixture reports/github-fixture.json --output reports/github-api-1381-summary.json --format json
extract-rollout parses Codex JSONL structurally and writes bounded summaries so image/base64 payloads do not become
the review surface. import-github imports a replayable fixture with stable source ids. plan evaluate checks
reports/dogfood-failure-catalog.json against reports/dogfood-evidence-sources.json and fails closed when referenced
sources are missing or stale.
Plugins
Plugins extend EAC without forcing every optional diagnostic or migration into the CLI host.
The boundary is intentionally strict. Core owns mandatory EAC host behavior: templates, guidance precedence, stable
contracts, safety gates, artifact persistence, plugin runtime loading, and the rules for authoring and controlling
Eternet pipelines. Plugins own optional diagnostics, repository-specific migration helpers, transient package migrations,
custom transformers, and first-party command families that intentionally stay outside Core implementation, such as the
built-in EAC.Plugin.Plans plan-folder surface.
Built-in plugins are first-party plugins admitted by the current CLI build. They can be carried as normal package or project references, but they still implement IEacPlugin and stay outside Eternet.Agents.Control.Core. Built-in does not mean "merge into Core"; it means "available without repo/global install because this CLI version deliberately ships it." Transient or environment-specific plugins such as the catalog EAC.Plugin.Extension.Assertions, EAC.Plugin.Extension.LegacyDB, and EAC.Plugin.Extension.ServiceFabric packages stay opt-in by default and should not become Core implementation.
Reusable plugin work can start in the sibling Eternet.Agents.Control.Plugins repository. If it becomes first-party and needs closer maintenance with EAC, either pin its package as a built-in CLI dependency or move the whole plugin project into this repository beside Core. In both cases the plugin boundary remains the same so agents and developers can keep creating plugins without risking Core behavior.
flowchart LR
BuiltIn["Built-in CLI references"] --> Runtime["Plugin runtime"]
Catalog["Plugin catalog service"] --> Install["eac plugins install"]
Local["Local dll/nupkg/directory/url"] --> Inspect["eac plugins inspect"]
Inspect --> Install
Install --> Store["repo/global plugin store"]
Store --> Runtime
Runtime --> Diagnose["diagnose loads plugin analyzers and providers"]
Runtime --> CodeFix["remediation apply-codefix dispatches plugin providers"]
What plugins can contribute today:
- Roslyn analyzer assemblies discovered from standard NuGet analyzer layout.
IEacDiagnosticProviderdiagnostics for non-Roslyn or source-only scans.- Roslyn-dotnet-format code-fix metadata through an
IEacPluginadapter. IEacTransformerProvidermigrations for operations that do not fit normal Roslyn code fixes.- Manifest metadata: capabilities, permissions, package ID, minimum EAC version, and plugin API version.
Commands:
eac plugins inspect --path <dll-or-nupkg-or-directory-or-url> --format json
eac plugins install --package EAC.Plugin.Extension.Assertions --workspace <repo> --scope repo --format json
eac plugins install --package <package-id> --version <version> --nuget --workspace <repo> --scope repo --format json
eac plugins install --path <local-or-http-nupkg> --workspace <repo> --scope repo --format json
eac plugins list --workspace <repo> --format json
eac plugins list --scope built-in --format json
eac plugins list --workspace <repo> --scope all --format json
eac plugins uninstall --package <package-id> --workspace <repo> --scope repo --format json
Repo-scoped plugins live under <workspace>/.eac/plugins. Global plugins live in the user plugin store or EAC_PLUGIN_GLOBAL_STORE when set. Built-in plugins are read-only first-party CLI references carried by the CLI package itself. They still implement IEacPlugin and are resolved through the same manifest/capability contract as external plugins, but they do not require repo or global installation.
For local development, first-party built-ins that live in this repository are referenced as sibling projects when the CLI is restored with EacIncludeBuiltInPluginPackageReferences=true. Opt-in catalog plugins that are deliberately kept outside this repository, such as EAC.Plugin.Extension.Assertions, EAC.Plugin.Extension.LegacyDB, and EAC.Plugin.Extension.ServiceFabric, come from the private catalog or local package feeds. Because this repo uses NuGet package source mapping, local dogfooding for external plugin packages needs a temporary NuGet config that maps the external package ID family to that feed.
EAC.Plugin.Extension.ServiceFabric intentionally stays in that external catalog lane for now. It is
Eternet-specific operational tooling, depends on environment-specific endpoints and the read-only svc-eac-sfdiag
identity, and should keep its own rollout cadence instead of becoming a built-in CLI dependency before deploy/restart/
upgrade workflows are proven.
The normal install path is global because the Service Fabric profile is machine/operator configuration, not repository state:
eac plugins install --package EAC.Plugin.Extension.ServiceFabric --scope global --format json
After install, sf doctor diagnoses host/config/node prerequisites without requiring --workspace. sf bootstrap --apply
stays bounded to local global EAC artifacts under service-fabric/ in EAC_CONFIG_HOME or %USERPROFILE%/.eac, and never
installs software or mutates remote nodes. Supplying --workspace <repo> only enables source-repo enrichment.
Built-In And Opt-In Inventory
The current built-in plugin stack shipped by the CLI includes analyzer catalog, built-in recipes, contracts, CRUD relational, legacy mediator-generator compatibility, feature-folder, localization, mediator, naming, OData, plan folders, review/source diagnostics, and validation plugins. A local dogfood build may also carry a pinned assertion-migration package as built-in; that is still plugin admission, not Core ownership.
The sibling Eternet.Agents.Control.Plugins repository currently carries opt-in catalog packages:
EAC.Plugin.Extension.Assertionswith aliaseac assertions migrate.EAC.Plugin.Extension.LegacyDBwith aliaseac legacy-query export.EAC.Plugin.Extension.ServiceFabricwith aliaseac sf ....
Use eac plugins list --scope built-in --format json to inspect the built-in set in the installed CLI, and
eac services operations --service plugins --format json or eac plugins install --package <package> to consume the
catalog.
<details> <summary>Example: inspecting the assertion migration plugin</summary>
Command:
eac plugins inspect --path D:/src/Chat/Eternet.Agents.Control.Plugins/artifacts/nupkg/EAC.Plugin.Extension.Assertions.0.1.0.nupkg --format json
Trimmed output:
{
"success": true,
"plugins": [
{
"pluginId": "EAC.Plugin.Extension.Assertions",
"packageId": "EAC.Plugin.Extension.Assertions",
"displayName": "Assertion Package Migrations",
"version": "0.1.0",
"description": "Detects and migrates FluentAssertions package references to AwesomeAssertions.",
"pluginApiVersion": "2.0",
"minimumEacVersion": "2.0.17",
"capabilities": ["EPKG002"],
"permissions": ["readWorkspace", "writeWorkspace", "network"],
"diagnostics": ["EPKG002"],
"codeFixes": ["EPKG002"],
"transformers": ["EPKG002"]
}
],
"warnings": []
}
</details>
The assertion migration plugin migrates FluentAssertions package metadata and supported C# using directives to AwesomeAssertions. Future migration candidates are tracked in docs/PLUGINS_TODO.md.
Queryable Plugin Output V2 Cutover
Queryable plugin operations now ship on the stable plugin API v2 contract.
Use the existing dataset runtime when the plugin output is naturally row-oriented:
- inventory or catalog rows;
- findings, events, logs, or other repeated records;
- data that users need to page, filter, sort, or project into a small set of columns;
- results that benefit from persisted reuse through
--persist-resultand--result-id.
Prefer a disclosure-style command instead when the output is one nested object or mixed graph and the caller is more likely
to ask for summary, page, or full than for arbitrary select / filter queries. Keep mutation commands such as
assertions migrate and sf bootstrap on bounded summary / preview output instead of flattening them into a default
dataset contract.
ADR 0003 vocabulary is intentional:
- disclosure and simple list paging use
--skip/--take; - dataset query paging uses
--skip/--top; - do not add
--topaliases to disclosure commands or--takealiases to dataset commands.
Compact-by-default examples:
eac services show --service legacy-db --format json
eac guidance show --id plan-folders --format text
eac sf inventory --workspace <repo> --top 5 --count --format json
Full-detail or follow-up escapes:
eac services show --service legacy-db --detail full --format json
eac guidance show --id plan-folders --detail full --take 1 --format text
eac sf inventory --workspace <repo> --dataset live-nodes --select name,status --orderby "name asc" --top 25 --persist-result --format json
eac sf inventory --workspace <repo> --dataset live-nodes --result-id <persisted-result-id> --top 25 --format json
Legacy eac guidance show --id plan-folders --full --format text remains accepted for compatibility, but it resolves to
the same bounded full-detail page and still emits continuation or artifact hints when more content exists than one inline
response can safely carry.
The built-in EAC.Plugin.Plans metadata remains the reference implementation for dataset-backed plugin commands in source,
even though the current host-owned plan root command still has a query-flag parity gap. Treat that gap as host-surface
debt, not as evidence that the dataset runtime is missing.
Breaking changes for callers:
- Stop parsing primary
payload.resultJson; migrated commands now keep JSON compact by default and expose datasets, counts, findings, artifacts, render hints, and an optional boundedpayloadobject. - Treat text and JSON as two renderings of the same dataset-first envelope. The default preview is bounded and the same query options drive both renderers.
- Use host-owned query/cache options instead of plugin-specific paging flags:
--dataset,--select,--filter,--orderby,--skip,--top,--count,--persist-result, and--result-id. --selectaccepts repeated values or a comma-separated list, for example--select operationId --select groupNameand--select operationId,groupNameare equivalent.
Cache and refresh behavior:
- Fresh execution is the default. Run the plugin command without
--result-idto query the live/source data again. - Reuse is explicit. Pass
--result-id <id>to query a persisted SQLite result without invoking the plugin provider again. - A result is persisted when the user passes
--persist-resultor when the plugin dataset declarescacheHint.defaultModeaspersisted. - JSON output includes
createdAtUtc,expiresAtUtc,persistedResult,reusedResult, and each dataset page'sskip,top,returnedCount,totalCount, andhasMorevalues. Text output prints the data creation time, cache expiration when present, and a next-page hint when more rows are available. - Persisted query results are stored under
EAC_PLUGIN_RESULTS_ROOTwhen set. On Windows, the default root is%LOCALAPPDATA%/EAC/plugin-results; older%USERPROFILE%/.eac/plugin-resultsresults are still readable by id. - On Windows, EAC stages the SQLite native dependency in a short writable path before opening local datasets. Override
that path with
EAC_SQLITE_NATIVE_ROOTif an environment needs a specific location.
Dogfood closed the cutover on the stable 2.0.17 package line:
eac plugins inspect --path D:/src/Chat/Eternet.Agents.Control.Plugins/artifacts/nupkg/EAC.Plugin.Extension.ServiceFabric.0.1.0.nupkg --format json
eac plugins install --path D:/src/Chat/Eternet.Agents.Control.Plugins/artifacts/nupkg/EAC.Plugin.Extension.ServiceFabric.0.1.0.nupkg --workspace D:/src/Chat/Eternet.Agents.Control.Plugins --scope repo --format json
eac sf inventory --workspace D:/src/Chat/Eternet.Agents.Control.Plugins --format json --top 5 --count
eac sf inventory --workspace D:/src/Chat/Eternet.Agents.Control.Plugins --dataset live-nodes --select name,healthState,status --orderby "name asc" --top 2 --count --result-id <persisted-result-id> --format json
The same contract now covers the LegacyDB migration plugin:
eac plugins inspect --path D:/src/Chat/Eternet.Agents.Control.Plugins/artifacts/nupkg/EAC.Plugin.Extension.LegacyDB.0.1.0.nupkg --format json
eac legacy-query export --workspace <target-workspace> --source-workspace <source-workspace> --wave-file docs/endpoint-migration/plans/waves/billing.md --service Eternet.Billing --operation-namespace BillingApi --group Billing_Route --declared-only --emit-query-code --dataset legacy-query-endpoints --select operationName --select suggestedContractsPath --orderby "operationName asc" --top 2 --count --format json
Templates
eac templates list --format json
eac templates show --template eternet-sf-webapi --format json
eac templates install --package Eternet.ServiceFabric.WebApi.Template --format json
eac templates update --package Eternet.ServiceFabric.WebApi.Template --format json
eac templates update --package Eternet.ServiceFabric.WebApi.Template --apply --format json
eac templates create --template eternet-sf-webapi --name MyService --output D:/src/MyService --format json
eac templates create --template eternet-sf-webapi --name MyService --output D:/src/MyService --apply --format json
Create and update commands dry-run by default. Add --apply for mutation.
Services And Auth
Services are allowlisted internal HTTP APIs discovered through OpenAPI.
eac services list --format json
eac services show --service legacy-db --detail summary --format json
eac services show --service legacy-db --detail full --format json
eac services operations --service legacy-db --skip 0 --take 25 --format json
eac services operation --service legacy-db --operation ListProcedures --format json
eac services schemas --service legacy-db --detail summary --format json
eac services schemas --service legacy-db --search CloneSession --detail page --skip 0 --take 25 --format json
eac services operation-schema --service legacy-db --operation CreateCloneSession --format json
eac services health --service legacy-db --format json
eac services invoke --service legacy-db --operation ListProcedures --param page=1 --param pageSize=50 --format json
eac services invoke --service gateway-authz --operation CurrentUserBatchAuthorize --approval-id <approval-id> --format json
eac services operations --service plugins --format json
eac services operations --service gateway-authz --format json
Authenticated services use stored EAC auth tokens:
eac auth login --server http://db.eternet.cc:5080 --provider github
eac auth status --server http://db.eternet.cc:5080 --provider github --format json
eac auth token list --server http://db.eternet.cc:5080 --provider github --format json
eac auth token revoke --server http://db.eternet.cc:5080 --provider github --id <token-id> --format json
eac auth approval request --namespace Auth --route-template /Auth/Me/Authorize/Batch --operation Read --permission-key Auth.Me.AuthorizeBatch.Read --reason "temporary override" --format json
eac auth approval status --id <approval-id> --format json
eac auth approval cancel --id <approval-id> --reason "no longer needed" --format json
eac auth logout --server http://db.eternet.cc:5080 --provider github --format json
Gateway/Auth authority settings:
EAC_AUTH_SERVER_URL: default auth server used byeac authcommands.EAC_GATEWAY_BASE_URL: gateway service catalog base URL (defaulthttps://api.eternet.cc).EAC_GATEWAY_AUTH_SERVER_URL: gateway auth authority override when auth and API hosts differ.
Company mode authorization checks fail closed for missing tokens, expired tokens, and unreachable gateway refresh calls.
Company mode now uses Windows secure storage by default. Set EAC_AUTH_MODE=local-dev to keep plaintext JSON
(~/.eac/auth.json) explicitly, or use an auth write operation to migrate legacy JSON into the secure store.
Mutating service calls require --apply.
Legacy DB
Snapshot commands operate against the legacy DB snapshot service. Testing commands scaffold and refresh repo-local Firebird metadata test assets.
eac legacy-db snapshots status --format json
eac legacy-db snapshots versions --format json
eac legacy-db snapshots show --version <version> --format json
eac legacy-db snapshots download --version <version> --output <path> --format json
eac legacy-db snapshots create --apply --format json
eac legacy-db testing scaffold --workspace <repo> --snapshot-root tests/LegacyDb --format json
eac legacy-db testing refresh --workspace <repo> --snapshot-root tests/LegacyDb --version <version> --format json
eac legacy-db testing inspect --workspace <repo> --format json
Use legacy-db testing refresh for metadata fixtures. Use the legacy-db service catalog commands for full clone-session workflows.
Read-Only AI Reasoning
eac ai reason --workspace <repo> --backend copilot --prompt "Summarize current diagnostics"
eac ai reason --workspace <repo> --backend codex --prompt "Explain the remediation plan"
AI reasoning is advisory and read-only. It does not replace diagnose, remediation, or verify evidence.
Agent Workflow
flowchart TD
A["Discover installed surface"] --> B["Load focused guidance"]
B --> C["Inspect tooling health"]
C --> D["Run fresh diagnose"]
D --> E["Page stored diagnostics"]
E --> F["Plan remediation or cleanup"]
F --> G["Dry-run deterministic fixes"]
G --> H["Apply only when EAC says safe"]
H --> I["Manual or agent edits"]
I --> J["Verify fresh evidence"]
Copyable baseline:
eac capabilities --format json
eac guidance show --id eac-agent-loop --format text
eac tooling inspect --workspace <repo> --profile all --format json
eac diagnose all --workspace <repo> --target <project-or-solution> --format json
eac diagnose list --workspace <repo> --from-run <run-id> --source eac --take 50 --format json
eac remediation status --workspace <repo> --from-run <run-id> --format json
eac remediation waves --workspace <repo> --from-run <run-id> --emit-plan .eac/remediation/waves.md --format json
eac remediation apply-codefix --workspace <repo> --from-run <run-id> --diagnostic <id> --format json
eac verify --workspace <repo> --target <change-name> --build-target <project-or-solution> --format json
Relationship With Agent Skills
The eac-harness agent skill is only a bootstrap layer. It tells an agent to check eac --version, discover eac capabilities, load eac guidance, use fresh diagnostics, and prefer EAC-owned deterministic remediation when safe. The CLI remains the versioned source of truth.
Release Flow
GitHub Releases are the review boundary. Publishing an eac-cli-v* release triggers the deterministic NuGet publishing workflow for the global tool.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.28 | 38 | 6/6/2026 |
| 2.0.27 | 51 | 6/5/2026 |
| 2.0.26 | 49 | 6/4/2026 |
| 2.0.25 | 74 | 6/3/2026 |
| 2.0.24 | 100 | 6/1/2026 |
| 2.0.23 | 106 | 5/30/2026 |
| 2.0.22 | 101 | 5/29/2026 |
| 2.0.21 | 100 | 5/28/2026 |
| 2.0.20 | 105 | 5/27/2026 |
| 2.0.19 | 102 | 5/26/2026 |
| 2.0.18 | 96 | 5/25/2026 |
| 2.0.17 | 96 | 5/24/2026 |
| 2.0.16 | 96 | 5/20/2026 |
| 2.0.15 | 113 | 5/19/2026 |
| 2.0.14 | 102 | 5/18/2026 |
| 2.0.13 | 96 | 5/17/2026 |
| 2.0.12 | 99 | 5/16/2026 |
| 2.0.11 | 104 | 5/15/2026 |
| 2.0.10 | 106 | 5/14/2026 |
| 2.0.9 | 106 | 5/13/2026 |