diff options
Diffstat (limited to 'src/Agent.App/Cli')
| -rw-r--r-- | src/Agent.App/Cli/CommandLine.cs | 102 |
1 files changed, 84 insertions, 18 deletions
diff --git a/src/Agent.App/Cli/CommandLine.cs b/src/Agent.App/Cli/CommandLine.cs index 3fdac9f..3b3fde1 100644 --- a/src/Agent.App/Cli/CommandLine.cs +++ b/src/Agent.App/Cli/CommandLine.cs @@ -1,38 +1,104 @@ namespace Agent.App.Cli; -public enum AppCommand { Serve, Check } +public enum AppCommand +{ + Serve, + Check, + ExecutableResolve, + ExecutableApprove, + ExecutableList, + ExecutableRevoke, + SandboxResolve, + SandboxConfirm, + SandboxShow +} -public sealed record CommandLine(AppCommand Command, string? ConfigPath, string? Language, string? Transport) +public sealed record CommandLine( + AppCommand Command, + string? ConfigPath, + string? Language, + string? Transport, + string? Alias = null, + string? ExecutablePath = null, + string? RuntimeRoot = null, + bool NoRuntime = false, + bool Yes = false, + string Format = "text") { public static CommandLine Parse(string[] args) { bool implicitServe = args.Length == 0 || args[0].StartsWith("--", StringComparison.Ordinal); - AppCommand command = implicitServe ? AppCommand.Serve : args[0] switch + int index = implicitServe ? 0 : 1; + AppCommand command; + string? alias = null; + if (implicitServe) command = AppCommand.Serve; + else if (args[0] == "serve") command = AppCommand.Serve; + else if (args[0] == "check") command = AppCommand.Check; + else if (args[0] is "executable" or "sandbox") { - "serve" => AppCommand.Serve, - "check" => AppCommand.Check, - _ => throw new CommandLineException("Expected 'serve' or 'check'.") - }; + if (index >= args.Length) throw new CommandLineException($"Expected a subcommand after '{args[0]}'."); + string subcommand = args[index++]; + command = (args[0], subcommand) switch + { + ("executable", "resolve") => AppCommand.ExecutableResolve, + ("executable", "approve") => AppCommand.ExecutableApprove, + ("executable", "list") => AppCommand.ExecutableList, + ("executable", "revoke") => AppCommand.ExecutableRevoke, + ("sandbox", "resolve") => AppCommand.SandboxResolve, + ("sandbox", "confirm") => AppCommand.SandboxConfirm, + ("sandbox", "show") => AppCommand.SandboxShow, + _ => throw new CommandLineException($"Unknown subcommand '{args[0]} {subcommand}'.") + }; + if (command is AppCommand.ExecutableResolve or AppCommand.ExecutableApprove or AppCommand.ExecutableRevoke) + { + if (index >= args.Length || args[index].StartsWith("--", StringComparison.Ordinal)) + throw new CommandLineException($"Executable Alias is required for '{args[0]} {subcommand}'."); + alias = args[index++]; + } + } + else throw new CommandLineException("Expected 'serve', 'check', 'executable', or 'sandbox'."); string? config = null; string? language = null; string? transport = null; - for (int i = implicitServe ? 0 : 1; i < args.Length; i++) + string? executablePath = null; + string? runtimeRoot = null; + bool noRuntime = false; + bool yes = false; + string format = "text"; + while (index < args.Length) { - string option = args[i]; - if (i + 1 >= args.Length) throw new CommandLineException($"Missing value for '{option}'."); - string value = args[++i]; + string option = args[index++]; switch (option) { - case "--config" when config is null: config = value; break; - case "--lang" when language is null: language = value; break; - case "--transport" when command == AppCommand.Serve && transport is null && value is "stdio" or "http": transport = value; break; - case "--transport" when command == AppCommand.Check: throw new CommandLineException("--transport is only valid for serve."); - case "--transport": throw new CommandLineException("Transport must be stdio or http."); - default: throw new CommandLineException($"Unknown or duplicate option '{option}'."); + case "--yes" when !yes: yes = true; break; + case "--no-runtime" when !noRuntime && runtimeRoot is null: noRuntime = true; break; + case "--config" when config is null: config = Value(option); break; + case "--lang" when language is null: language = Value(option); break; + case "--transport" when command == AppCommand.Serve && transport is null: + transport = Value(option); + if (transport is not ("stdio" or "http")) throw new CommandLineException("Transport must be stdio or http."); + break; + case "--path" when executablePath is null: executablePath = Value(option); break; + case "--runtime-root" when runtimeRoot is null && !noRuntime: runtimeRoot = Value(option); break; + case "--format" when command == AppCommand.SandboxShow: + format = Value(option); + if (format is not ("text" or "json")) throw new CommandLineException("Format must be text or json."); + break; + default: throw new CommandLineException($"Unknown, duplicate, or invalid option '{option}' for this command."); } } - return new CommandLine(command, config, language, transport); + bool management = command is not (AppCommand.Serve or AppCommand.Check); + if (management && config is null) throw new CommandLineException("--config <file> is required for executable and sandbox commands."); + if (yes && command is not (AppCommand.ExecutableApprove or AppCommand.ExecutableRevoke or AppCommand.SandboxConfirm)) + throw new CommandLineException("--yes is valid only for approve, revoke, and confirm."); + return new(command, config, language, transport, alias, executablePath, runtimeRoot, noRuntime, yes, format); + + string Value(string optionName) + { + if (index >= args.Length) throw new CommandLineException($"Missing value for '{optionName}'."); + return args[index++]; + } } } |
