Skip to content

Commit 223b20d

Browse files
Add live operation automation parity
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 6f7727e commit 223b20d

File tree

14 files changed

+1106
-35
lines changed

14 files changed

+1106
-35
lines changed

cli-arguments.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323
| `--automation show-app` | Asks the running UniGetUI instance to show and focus its main window when a UI session exists | 2026.1+ |
2424
| `--automation navigate-app --page {discover\|updates\|installed\|bundles\|settings\|managers\|own-log\|manager-log\|operation-history\|help\|release-notes\|about} [--manager name] [--help-attachment path]` | Navigates the running UI session to a top-level destination, with optional manager-specific or help-page context where supported | 2026.1+ |
2525
| `--automation quit-app` | Gracefully shuts down the current UniGetUI session, including the headless automation daemon | 2026.1+ |
26+
| `--automation list-operations` | Lists tracked live and completed operations, including queue state, current status line, retry modes, and package identity where available | 2026.1+ |
27+
| `--automation get-operation --operation-id id` | Returns the full tracked payload for one operation, including current state, queue actions, retry modes, and captured output lines | 2026.1+ |
28+
| `--automation get-operation-output --operation-id id [--tail n]` | Returns captured live output for one operation, optionally limited to the last _n_ lines | 2026.1+ |
29+
| `--automation wait-operation --operation-id id [--timeout seconds] [--delay seconds]` | Polls the local automation service until the specified operation finishes and returns the final tracked payload | 2026.1+ |
30+
| `--automation cancel-operation --operation-id id` | Cancels a queued or running operation through the same operation pipeline used by the UI | 2026.1+ |
31+
| `--automation retry-operation --operation-id id [--mode {retry\|retry-as-admin\|retry-interactive\|retry-no-hash-check}]` | Re-runs a finished operation using one of the retry modes supported by the UI for that operation | 2026.1+ |
32+
| `--automation reorder-operation --operation-id id --action {run-now\|run-next\|run-last}` | Reorders a queued operation in the shared operation queue | 2026.1+ |
33+
| `--automation forget-operation --operation-id id` | Removes a finished operation from the tracked live-operation list without altering persisted history | 2026.1+ |
2634
| `--automation get-version` | Reads the local automation service build number through the background API | 2026.1+ |
2735
| `--automation get-updates` | Reads the currently available updates through the local automation service and returns structured JSON | 2026.1+ |
2836
| `--automation list-managers` | Lists package managers, readiness, executable metadata, and automation-relevant capability flags | 2026.1+ |
@@ -71,9 +79,9 @@
7179
| `--automation search-packages --manager name --query text [--max-results n]` | Searches packages through the automation service and returns structured JSON | 2026.1+ |
7280
| `--automation package-details --manager name --package-id id` | Fetches the package-details payload currently exposed through the automation layer | 2026.1+ |
7381
| `--automation package-versions --manager name --package-id id` | Lists installable versions for a package when the manager supports custom versions | 2026.1+ |
74-
| `--automation install-package --manager name --package-id id [--version v] [--scope scope] [--pre-release] [--elevated true\|false] [--interactive true\|false] [--skip-hash true\|false] [--architecture value] [--location path]` | Installs a package through the automation service and waits for completion, honoring the same core install options exposed by the UI | 2026.1+ |
75-
| `--automation download-package --manager name --package-id id --output path` | Downloads a package installer or artifact to the specified file or directory and returns the resolved saved path | 2026.1+ |
76-
| `--automation reinstall-package --manager name --package-id id [--version v] [--scope scope] [--pre-release] [--elevated true\|false] [--interactive true\|false] [--skip-hash true\|false] [--architecture value] [--location path]` | Re-runs package installation for an installed package using the requested install options | 2026.1+ |
82+
| `--automation install-package --manager name --package-id id [--version v] [--scope scope] [--pre-release] [--elevated true\|false] [--interactive true\|false] [--skip-hash true\|false] [--architecture value] [--location path] [--wait true\|false \| --detach]` | Installs a package through the automation service; async mode returns immediately with an operation id so agents can inspect, wait, cancel, or forget the operation separately | 2026.1+ |
83+
| `--automation download-package --manager name --package-id id --output path [--wait true\|false \| --detach]` | Downloads a package installer or artifact to the specified file or directory; async mode returns the tracked download operation id immediately | 2026.1+ |
84+
| `--automation reinstall-package --manager name --package-id id [--version v] [--scope scope] [--pre-release] [--elevated true\|false] [--interactive true\|false] [--skip-hash true\|false] [--architecture value] [--location path] [--wait true\|false \| --detach]` | Re-runs package installation for an installed package using the requested install options, optionally as a detached tracked operation | 2026.1+ |
7785
| `--automation open-window` | Legacy alias for `--automation show-app` | 2026.1+ |
7886
| `--automation open-updates` | Legacy alias for `--automation navigate-app --page updates` | 2026.1+ |
7987
| `--automation show-package --package-id id --package-source source` | Opens the package details flow for the specified package | 2026.1+ |
@@ -82,9 +90,9 @@
8290
| `--automation unignore-package --manager name --package-id id [--version v]` | Removes an ignored-update rule for a package and refreshes the updates view | 2026.1+ |
8391
| `--automation update-all` | Queues updates for all packages currently shown as upgradable | 2026.1+ |
8492
| `--automation update-manager --manager name` | Queues updates for all packages handled by the specified manager | 2026.1+ |
85-
| `--automation update-package --manager name --package-id id [--version v] [--scope scope] [--pre-release] [--elevated true\|false] [--interactive true\|false] [--skip-hash true\|false] [--architecture value] [--location path]` | Updates a specific package through the automation service and waits for completion | 2026.1+ |
86-
| `--automation uninstall-package --manager name --package-id id [--scope scope] [--remove-data true\|false] [--elevated true\|false] [--interactive true\|false]` | Uninstalls a package through the automation service and waits for completion | 2026.1+ |
87-
| `--automation uninstall-then-reinstall-package --manager name --package-id id [--version v] [--scope scope] [--pre-release] [--remove-data true\|false] [--elevated true\|false] [--interactive true\|false] [--skip-hash true\|false] [--architecture value] [--location path]` | Uninstalls an installed package and then immediately reinstalls it through the shared operation pipeline | 2026.1+ |
93+
| `--automation update-package --manager name --package-id id [--version v] [--scope scope] [--pre-release] [--elevated true\|false] [--interactive true\|false] [--skip-hash true\|false] [--architecture value] [--location path] [--wait true\|false \| --detach]` | Updates a specific package through the automation service, either synchronously or as a tracked background operation | 2026.1+ |
94+
| `--automation uninstall-package --manager name --package-id id [--scope scope] [--remove-data true\|false] [--elevated true\|false] [--interactive true\|false] [--wait true\|false \| --detach]` | Uninstalls a package through the automation service, either synchronously or as a tracked background operation | 2026.1+ |
95+
| `--automation uninstall-then-reinstall-package --manager name --package-id id [--version v] [--scope scope] [--pre-release] [--remove-data true\|false] [--elevated true\|false] [--interactive true\|false] [--skip-hash true\|false] [--architecture value] [--location path] [--wait true\|false \| --detach]` | Uninstalls an installed package and then immediately reinstalls it through the shared operation pipeline, with the same async tracking support as other package actions | 2026.1+ |
8896
| `--background-api-transport {tcp\|named-pipe}` | Selects which local HTTP transport UniGetUI uses for the background API when the app starts | 2026.1+ |
8997
| `--background-api-port port` | Overrides the localhost TCP port used by the background API when `--background-api-transport tcp` is active | 2026.1+ |
9098
| `--background-api-pipe-name name` | Overrides the Windows named pipe name used by the background API when `--background-api-transport named-pipe` is active | 2026.1+ |
@@ -102,7 +110,7 @@
102110

103111
- `dotnet src\UniGetUI.Avalonia\bin\Release\net10.0\UniGetUI.Avalonia.dll --headless` starts the local automation daemon without opening any window or requiring a graphical desktop session.
104112
- `dotnet src\UniGetUI.Cli\bin\Release\net10.0\UniGetUI.Cli.dll <command>` is the cross-platform CLI wrapper for the automation service. It automatically prepends `--automation`, so `UniGetUI.Cli status` and `UniGetUI.Cli search-packages --manager ".NET Tool" --query dotnetsay` work directly.
105-
- Current agent-oriented command coverage includes app/session lifecycle inspection and shutdown, manager/source inspection plus manager enablement, notification suppression, manager-maintenance and executable-path control, settings and secure-settings inspection/mutation, desktop-shortcut state management, app/history/manager log inspection, local backup creation and GitHub cloud-backup/auth flows, current bundle inspection/import/export/add/remove/install flows, package search/details/version listing, ignored-update management, and package install/update/uninstall flows.
113+
- Current agent-oriented command coverage includes app/session lifecycle inspection and shutdown, live operation inspection/control (`list/get/output/wait/cancel/retry/reorder/forget`), manager/source inspection plus manager enablement, notification suppression, manager-maintenance and executable-path control, settings and secure-settings inspection/mutation, desktop-shortcut state management, app/history/manager log inspection, local backup creation and GitHub cloud-backup/auth flows, current bundle inspection/import/export/add/remove/install flows, package search/details/version listing, ignored-update management, and package install/update/uninstall/download/reinstall flows with optional detached execution.
106114

107115
<br><br>
108116
# `unigetui://` deep link

src/UniGetUI.Avalonia/App.axaml.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
using Avalonia.Markup.Xaml.Styling;
55
using Avalonia.Platform;
66
using Avalonia.Styling;
7+
#if AVALONIA_DIAGNOSTICS_ENABLED
8+
using Avalonia.Diagnostics;
9+
#endif
710
using UniGetUI.Avalonia.Infrastructure;
811
using UniGetUI.Avalonia.Views;
912
using UniGetUI.PackageEngine;

src/UniGetUI.Avalonia/Infrastructure/AvaloniaOperationRegistry.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using UniGetUI.Core.Logging;
99
using UniGetUI.Core.SettingsEngine;
1010
using UniGetUI.Core.Tools;
11+
using UniGetUI.Interface;
1112
using UniGetUI.PackageEngine.Classes.Packages.Classes;
1213
using UniGetUI.PackageEngine.Enums;
1314
using UniGetUI.PackageOperations;
@@ -32,6 +33,7 @@ public static class AvaloniaOperationRegistry
3233
/// </summary>
3334
public static void Add(AbstractOperation op)
3435
{
36+
AutomationOperationApi.Track(op);
3537
var vm = new OperationViewModel(op);
3638

3739
Dispatcher.UIThread.Post(() =>
@@ -88,6 +90,10 @@ public static void Remove(OperationViewModel vm)
8890
Operations.Remove(vm.Operation);
8991
});
9092
while (AbstractOperation.OperationQueue.Remove(vm.Operation)) ;
93+
if (vm.Operation.Status is not (OperationStatus.InQueue or OperationStatus.Running))
94+
{
95+
AutomationOperationApi.ForgetTracking(vm.Operation.Metadata.Identifier);
96+
}
9197
}
9298

9399
private static async Task RemoveAfterDelayAsync(AbstractOperation op, int milliseconds)
@@ -98,6 +104,10 @@ private static async Task RemoveAfterDelayAsync(AbstractOperation op, int millis
98104
var vm = OperationViewModels.FirstOrDefault(v => v.Operation == op);
99105
if (vm is not null) OperationViewModels.Remove(vm);
100106
Operations.Remove(op);
107+
if (op.Status is not (OperationStatus.InQueue or OperationStatus.Running))
108+
{
109+
AutomationOperationApi.ForgetTracking(op.Metadata.Identifier);
110+
}
101111
});
102112
}
103113

src/UniGetUI.Interface.BackgroundApi/AutomationCliCommandRunner.cs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,105 @@ TextWriter error
5555
await client.NavigateAppAsync(BuildAppNavigateRequest(args))
5656
),
5757
"quit-app" => await WriteJsonAsync(output, await client.QuitAppAsync()),
58+
"list-operations" => await WriteJsonAsync(
59+
output,
60+
new
61+
{
62+
status = "success",
63+
operations = await client.ListOperationsAsync(),
64+
}
65+
),
66+
"get-operation" => await WriteJsonAsync(
67+
output,
68+
new
69+
{
70+
status = "success",
71+
operation = await client.GetOperationAsync(
72+
GetRequiredArgument(
73+
args,
74+
"--operation-id",
75+
"The get-operation automation command requires --operation-id."
76+
)
77+
),
78+
}
79+
),
80+
"get-operation-output" => await WriteJsonAsync(
81+
output,
82+
new
83+
{
84+
status = "success",
85+
output = await client.GetOperationOutputAsync(
86+
GetRequiredArgument(
87+
args,
88+
"--operation-id",
89+
"The get-operation-output automation command requires --operation-id."
90+
),
91+
GetOptionalIntArgument(args, "--tail")
92+
),
93+
}
94+
),
95+
"wait-operation" => await WriteJsonAsync(
96+
output,
97+
new
98+
{
99+
status = "success",
100+
operation = await client.WaitForOperationAsync(
101+
GetRequiredArgument(
102+
args,
103+
"--operation-id",
104+
"The wait-operation automation command requires --operation-id."
105+
),
106+
GetOptionalIntArgument(args, "--timeout") ?? 300,
107+
((GetOptionalIntArgument(args, "--delay") ?? 1) * 1000)
108+
),
109+
}
110+
),
111+
"cancel-operation" => await WriteJsonAsync(
112+
output,
113+
await client.CancelOperationAsync(
114+
GetRequiredArgument(
115+
args,
116+
"--operation-id",
117+
"The cancel-operation automation command requires --operation-id."
118+
)
119+
)
120+
),
121+
"retry-operation" => await WriteJsonAsync(
122+
output,
123+
await client.RetryOperationAsync(
124+
GetRequiredArgument(
125+
args,
126+
"--operation-id",
127+
"The retry-operation automation command requires --operation-id."
128+
),
129+
GetOptionalArgument(args, "--mode")
130+
)
131+
),
132+
"reorder-operation" => await WriteJsonAsync(
133+
output,
134+
await client.ReorderOperationAsync(
135+
GetRequiredArgument(
136+
args,
137+
"--operation-id",
138+
"The reorder-operation automation command requires --operation-id."
139+
),
140+
GetRequiredArgument(
141+
args,
142+
"--action",
143+
"The reorder-operation automation command requires --action."
144+
)
145+
)
146+
),
147+
"forget-operation" => await WriteJsonAsync(
148+
output,
149+
await client.ForgetOperationAsync(
150+
GetRequiredArgument(
151+
args,
152+
"--operation-id",
153+
"The forget-operation automation command requires --operation-id."
154+
)
155+
)
156+
),
58157
"list-managers" => await WriteJsonAsync(
59158
output,
60159
new
@@ -523,6 +622,9 @@ private static AutomationPackageActionRequest BuildPackageActionRequest(IReadOnl
523622
Interactive = GetOptionalBoolArgument(args, "--interactive"),
524623
SkipHash = GetOptionalBoolArgument(args, "--skip-hash"),
525624
RemoveData = GetOptionalBoolArgument(args, "--remove-data"),
625+
WaitForCompletion = args.Contains("--detach")
626+
? false
627+
: GetOptionalBoolArgument(args, "--wait"),
526628
Architecture = GetOptionalArgument(args, "--architecture"),
527629
InstallLocation = GetOptionalArgument(args, "--location"),
528630
OutputPath = GetOptionalArgument(args, "--output"),

0 commit comments

Comments
 (0)