From 87dd5e4ce9d33a5d2491d78ed0fddb07c8010dbc Mon Sep 17 00:00:00 2001 From: Paul Hinze Date: Mon, 18 May 2026 17:29:12 -0500 Subject: [PATCH 1/3] Group top-level CLI commands by user intent for clearer help output Prospect feedback flagged that miren's top-level help dumped a flat list of 30+ commands, with server-administration commands sitting right next to deploy and rollback. For someone who only ever deploys an app, that's a lot of noise to navigate around. Reorganizes top-level help into five named groups (Getting started, Monitoring your app, Configuring your app, Client operations, Server operations) so deployers see what they need first and the operator surface is still discoverable but visually separated. Headers render in bold yellow via lipgloss; sub-command counts dim. The rendering moved into the runtime layer. mflags now just exposes group metadata via the new CommandGroupProvider interface (see the companion PR mirendev/mflags#14), and the runtime walks the command tree and styles output itself. Same model means future help-rendering polish doesn't keep pulling presentation logic back into mflags. A drift-prevention test catches new top-level commands that forget to declare a group, so the grouping stays complete as the CLI grows. Closes MIR-845 --- cli/cli.go | 21 ++++++++ cli/commands/commands.go | 46 ++++++++++------- cli/commands/help.go | 13 +++++ cli/commands/help_alias.go | 88 -------------------------------- cli/commands/help_commands.go | 10 +++- cli/commands/help_groups.go | 27 ++++++++++ cli/commands/help_groups_test.go | 42 +++++++++++++++ cli/commands/help_render.go | 79 ++++++++++++++++++++++++++++ cli/commands/infer.go | 13 +++++ go.mod | 2 +- go.sum | 8 ++- 11 files changed, 239 insertions(+), 110 deletions(-) delete mode 100644 cli/commands/help_alias.go create mode 100644 cli/commands/help_groups.go create mode 100644 cli/commands/help_groups_test.go create mode 100644 cli/commands/help_render.go diff --git a/cli/cli.go b/cli/cli.go index dffd08b01..8b911ec4a 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -48,6 +48,11 @@ func Run(args []string) int { return 1 } + if shouldShowTopLevelHelp(execArgs) { + commands.RenderTopLevelHelp(d) + return 0 + } + err = d.Execute(execArgs) if err != nil { if errors.Is(err, context.Canceled) { @@ -66,6 +71,22 @@ func Run(args []string) int { return 0 } +// shouldShowTopLevelHelp returns true when the args indicate we should render +// top-level help (no args, or just -h/--help with no command). +func shouldShowTopLevelHelp(args []string) bool { + if len(args) == 0 { + return true + } + // Only help flags, no command words + for _, arg := range args { + if arg == "-h" || arg == "--help" { + continue + } + return false + } + return true +} + // printError renders an error to stderr. If the error implements // ui.TerminalError, it gets colorized multi-line output; otherwise // it falls back to a plain "ERROR: ..." line. diff --git a/cli/commands/commands.go b/cli/commands/commands.go index 965b50bdb..fb54c70b2 100644 --- a/cli/commands/commands.go +++ b/cli/commands/commands.go @@ -8,6 +8,7 @@ import ( func RegisterAll(d *mflags.Dispatcher) { // Core commands d.Dispatch("version", Infer("version", "Print the version", Version, + WithGroup(GroupClient), WithExample(mflags.Example{ Name: "Print version", Body: "miren version", @@ -18,6 +19,7 @@ func RegisterAll(d *mflags.Dispatcher) { }), )) d.Dispatch("login", Infer("login", "Authenticate with miren.cloud", Login, + WithGroup(GroupClient), WithExample(mflags.Example{ Name: "Login", Body: "miren login", @@ -28,12 +30,14 @@ func RegisterAll(d *mflags.Dispatcher) { }), )) d.Dispatch("logout", Infer("logout", "Remove local authentication credentials", Logout, + WithGroup(GroupClient), WithExample(mflags.Example{ Name: "Logout", Body: "miren logout", }), )) d.Dispatch("whoami", Infer("whoami", "Display information about the current authenticated user", Whoami, + WithGroup(GroupClient), WithExample(mflags.Example{ Name: "Show current user", Body: "miren whoami", @@ -46,6 +50,7 @@ func RegisterAll(d *mflags.Dispatcher) { // Doctor commands d.Dispatch("doctor", Infer("doctor", "Diagnose miren environment and connectivity", Doctor, + WithGroup(GroupClient), WithExample(mflags.Example{ Name: "Run all diagnostics", Body: "miren doctor", @@ -72,6 +77,7 @@ func RegisterAll(d *mflags.Dispatcher) { // App lifecycle commands d.Dispatch("init", Infer("init", "Initialize a new application", Init, + WithGroup(GroupGettingStarted), WithExample(mflags.Example{ Name: "Initialize in current directory", Body: "miren init", @@ -82,6 +88,7 @@ func RegisterAll(d *mflags.Dispatcher) { }), )) d.Dispatch("deploy", Infer("deploy", "Deploy an application", Deploy, + WithGroup(GroupGettingStarted), WithExample(mflags.Example{ Name: "Basic", Body: "miren deploy", @@ -114,6 +121,7 @@ miren deploy --analyze }), )) d.Dispatch("rollback", Infer("rollback", "Roll back to a previous version", Rollback, + WithGroup(GroupGettingStarted), WithExample(mflags.Example{ Name: "Rollback the app in the current directory", Body: "miren rollback", @@ -124,6 +132,7 @@ miren deploy --analyze }), )) d.Dispatch("logs", Infer("logs", "View logs (defaults to app logs)", LogsApp, + WithGroup(GroupMonitoring), WithDescription(logsDescription), WithExample(mflags.Example{ Name: "View logs for the current app", @@ -190,6 +199,7 @@ miren deploy --analyze // App management commands d.Dispatch("app", Infer("app", "Get information about an application", App, + WithGroup(GroupMonitoring), WithExample(mflags.Example{ Name: "Show app info for the current directory", Body: "miren app", @@ -287,6 +297,7 @@ miren deploy --analyze }), )) d.Dispatch("apps", Infer("apps", "List all applications (alias for 'app list')", AppList, + WithGroup(GroupMonitoring), WithExample(mflags.Example{ Name: "List all apps", Body: "miren apps", @@ -294,7 +305,7 @@ miren deploy --analyze )) // Sandbox commands - d.Dispatch("sandbox", Section("sandbox", "Sandbox management commands", "", WithSectionDescription(sandboxSectionDescription))) + d.Dispatch("sandbox", Section("sandbox", "Sandbox management commands", "", WithSectionDescription(sandboxSectionDescription), WithSectionGroup(GroupMonitoring))) d.Dispatch("sandbox list", Infer("sandbox list", "List sandboxes (excludes dead by default)", SandboxList, WithExample(mflags.Example{ Name: "List running sandboxes", @@ -338,7 +349,7 @@ miren deploy --analyze )) // Sandbox pool commands - d.Dispatch("sandbox-pool", Section("sandbox-pool", "Sandbox pool management commands", "")) + d.Dispatch("sandbox-pool", Section("sandbox-pool", "Sandbox pool management commands", "", WithSectionGroup(GroupMonitoring))) d.Dispatch("sandbox-pool list", Infer("sandbox-pool list", "List all sandbox pools", SandboxPoolList, WithExample(mflags.Example{ Name: "List all pools", @@ -353,7 +364,7 @@ miren deploy --analyze )) // Environment variable commands - d.Dispatch("env", Section("env", "Environment variable management commands", "")) + d.Dispatch("env", Section("env", "Environment variable management commands", "", WithSectionGroup(GroupConfiguring))) d.Dispatch("env set", Infer("env set", "Set environment variables for an application", EnvSet, WithExample(mflags.Example{ Name: "Set an environment variable", @@ -409,7 +420,7 @@ miren deploy --analyze // Addon commands (gated behind labs flag) if labs.Addons() { - d.Dispatch("addon", Section("addon", "Addon management commands", "")) + d.Dispatch("addon", Section("addon", "Addon management commands", "", WithSectionGroup(GroupConfiguring))) d.Dispatch("addon list-available", Infer("addon list-available", "List available addons", AddonListAvailable, WithLabsFeature(labs.FeatureAddons), WithExample(mflags.Example{ @@ -457,6 +468,7 @@ miren deploy --analyze // Route commands d.Dispatch("route", Infer("route", "List all HTTP routes", Route, + WithGroup(GroupConfiguring), WithExample(mflags.Example{ Name: "List all routes", Body: "miren route", @@ -544,7 +556,7 @@ miren deploy --analyze } // Config commands - d.Dispatch("config", Section("config", "Configuration file management", "")) + d.Dispatch("config", Section("config", "Configuration file management", "", WithSectionGroup(GroupClient))) d.Dispatch("config info", Infer("config info", "Show configuration file locations and format", ConfigInfo, WithExample(mflags.Example{ Name: "Show config info", @@ -564,6 +576,7 @@ miren deploy --analyze // Cluster commands d.Dispatch("cluster", Infer("cluster", "List configured clusters", Cluster, + WithGroup(GroupClient), WithExample(mflags.Example{ Name: "List clusters", Body: "miren cluster", @@ -622,7 +635,7 @@ miren deploy --analyze // Runner commands (distributed runners) - behind feature flag if labs.DistributedRunners() { - d.Dispatch("runner", Section("runner", "Runner management commands", "")) + d.Dispatch("runner", Section("runner", "Runner management commands", "", WithSectionGroup(GroupServer))) d.Dispatch("runner token", Section("runner token", "Manage join tokens", "")) d.Dispatch("runner token create", Infer("runner token create", "Create a join token for a runner", RunnerTokenCreate, WithLabsFeature(labs.FeatureDistributedRunners), @@ -755,6 +768,7 @@ miren deploy --analyze // Server commands d.Dispatch("server", Infer("server", "Start the miren server", Server, + WithGroup(GroupServer), WithExample(mflags.Example{ Name: "Start in standalone mode", Body: "miren server --mode standalone", @@ -834,7 +848,7 @@ miren deploy --analyze )) // CLI management commands - d.Dispatch("download", Section("download", "Download management commands", "")) + d.Dispatch("download", Section("download", "Download management commands", "", WithSectionGroup(GroupServer))) d.Dispatch("download release", Infer("download release", "Download and extract miren release", DownloadRelease, WithExample(mflags.Example{ Name: "Download the latest release", @@ -842,6 +856,7 @@ miren deploy --analyze }), )) d.Dispatch("upgrade", Infer("upgrade", "Upgrade miren CLI to latest version", Upgrade, + WithGroup(GroupClient), WithExample(mflags.Example{ Name: "Upgrade to latest", Body: "miren upgrade", @@ -857,7 +872,7 @@ miren deploy --analyze )) // Auth commands - d.Dispatch("auth", Section("auth", "Authentication commands", "")) + d.Dispatch("auth", Section("auth", "Authentication commands", "", WithSectionGroup(GroupConfiguring))) d.Dispatch("auth generate", Infer("auth generate", "Generate authentication config file", AuthGenerate, WithExample(mflags.Example{ Name: "Generate auth config", @@ -895,6 +910,7 @@ miren deploy --analyze // Admin commands d.Dispatch("admin", Infer("admin", "Call an admin method on an application", Admin, + WithGroup(GroupConfiguring), WithDescription(adminDescription), WithExample(mflags.Example{ Name: "List available admin methods", @@ -920,7 +936,7 @@ Use these commands to help diagnose issues with the miren runtime. Warning: These commands are intended for advanced users and developers. They may change or be removed without notice. -`)) +`, WithSectionGroup(GroupServer))) d.Dispatch("debug connection", Infer("debug connection", "Test connectivity and authentication with a server", DebugConnection)) d.Dispatch("debug advertise", Infer("debug advertise", "Show which addresses the server would advertise and why", DebugAdvertise)) d.Dispatch("debug reindex", Infer("debug reindex", "Rebuild all entity indexes from scratch", DebugReindex)) @@ -949,6 +965,7 @@ Warning: These commands are intended for advanced users and developers. They may d.Dispatch("debug entity ensure", Infer("debug entity ensure", "Ensure an entity exists", EntityEnsure)) // Disk commands + d.Dispatch("disk", Section("disk", "Disk backup and recovery", "", WithSectionGroup(GroupServer))) d.Dispatch("disk backup", Infer("disk backup", "Backup a disk to a snapshot file", DiskBackup)) d.Dispatch("disk restore", Infer("disk restore", "Restore a disk from a snapshot file", DiskRestore)) d.Dispatch("disk undelete", Infer("disk undelete", "Restore a recently deleted disk", DiskUndelete)) @@ -980,21 +997,14 @@ Warning: These commands are intended for advanced users and developers. They may d.Dispatch("debug netdb gc", Infer("debug netdb gc", "Find and release orphaned IP leases", DebugNetDBGC)) // Internal commands (hidden from help, used by miren internals) - d.Dispatch("internal", Section("internal", "Internal commands used by miren components", "")) + d.Dispatch("internal", Section("internal", "Internal commands used by miren components", "", WithSectionGroup(GroupHidden))) // Alias commands + d.Dispatch("alias", Section("alias", "CLI alias management", "", WithSectionGroup(GroupClient))) d.Dispatch("alias list", Infer("alias list", "List configured CLI aliases", AliasList)) // Help command (registered last so it can reference all other commands) d.Dispatch("help", NewHelpCommand(d)) - d.Dispatch("help alias", Infer("help alias", "Learn how to define and use CLI aliases", HelpAlias)) addCommands(d) } - -func HiddenCommands() []string { - return []string{ - "internal", - "debug", - } -} diff --git a/cli/commands/help.go b/cli/commands/help.go index dc67e3eec..0477d229c 100644 --- a/cli/commands/help.go +++ b/cli/commands/help.go @@ -11,6 +11,7 @@ type section struct { help string desc string description string + group string fs *mflags.FlagSet } @@ -25,6 +26,13 @@ func WithSectionDescription(desc string) SectionOption { } } +// WithSectionGroup assigns this section to a named group for help rendering. +func WithSectionGroup(group string) SectionOption { + return func(s *section) { + s.group = group + } +} + func Section(name, desc, help string, opts ...SectionOption) mflags.Command { help = strings.TrimSpace(help) @@ -77,3 +85,8 @@ func (s *section) Synopsis() string { func (s *section) Description() string { return s.description } + +// CommandGroup implements mflags.CommandGroupProvider. +func (s *section) CommandGroup() string { + return s.group +} diff --git a/cli/commands/help_alias.go b/cli/commands/help_alias.go deleted file mode 100644 index 4c9ce6e02..000000000 --- a/cli/commands/help_alias.go +++ /dev/null @@ -1,88 +0,0 @@ -package commands - -import ( - "fmt" - "os" - "sort" - "text/tabwriter" - - "miren.dev/runtime/appconfig" - "miren.dev/runtime/pkg/color" -) - -type helpAliasOpts struct{} - -func HelpAlias(ctx *Context, opts helpAliasOpts) error { - bold := color.New(color.Bold) - faint := color.New(color.Faint) - cyan := color.New(color.FgCyan) - green := color.New(color.FgGreen) - - bold.Println("CLI Aliases") - fmt.Println() - fmt.Println("Aliases let you define custom shortcuts for frequently-used commands.") - fmt.Printf("Define them in %s:\n", cyan.Sprint(appconfig.AppConfigPath)) - fmt.Println() - - faint.Println(" [aliases]") - faint.Println(` console = "app run bin/rails console"`) - faint.Println(` tail = "logs app -f"`) - fmt.Println() - - bold.Println("Usage") - fmt.Println() - fmt.Printf(" miren %s %s miren app run bin/rails console\n", - green.Sprint("console"), faint.Sprint("→")) - fmt.Printf(" miren %s -n 50 %s miren logs app -f -n 50\n", - green.Sprint("tail"), faint.Sprint("→")) - fmt.Println() - fmt.Println(" Extra arguments are appended to the expanded command.") - fmt.Println() - - bold.Println("Multi-word aliases") - fmt.Println() - fmt.Println(" Alias names can contain multiple words to create namespaces:") - fmt.Println() - faint.Println(` "x tail" = "logs app -f"`) - fmt.Println() - fmt.Printf(" miren %s %s miren logs app -f\n", - green.Sprint("x tail"), faint.Sprint("→")) - fmt.Println() - - bold.Println("Rules") - fmt.Println() - fmt.Println(" - Alias names must not shadow built-in commands.") - fmt.Println(" - Aliases expand once — an alias cannot reference another alias.") - fmt.Println(" - Names use lowercase letters, numbers, dashes, and underscores.") - fmt.Println() - - ac, err := appconfig.LoadAppConfig() - if err != nil { - printConfigWarning(err) - fmt.Println() - return nil - } - - if ac == nil || len(ac.Aliases) == 0 { - faint.Println("No aliases configured.") - fmt.Printf("Add an %s section to %s to get started.\n", - cyan.Sprint("[aliases]"), cyan.Sprint(appconfig.AppConfigPath)) - return nil - } - - bold.Println("Configured aliases") - fmt.Println() - - names := make([]string, 0, len(ac.Aliases)) - for name := range ac.Aliases { - names = append(names, name) - } - sort.Strings(names) - - w := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', 0) - for _, name := range names { - fmt.Fprintf(w, " %s\t%s %s\n", - green.Sprint(name), faint.Sprint("→"), ac.Aliases[name]) - } - return w.Flush() -} diff --git a/cli/commands/help_commands.go b/cli/commands/help_commands.go index 9594d5b04..6e4b80991 100644 --- a/cli/commands/help_commands.go +++ b/cli/commands/help_commands.go @@ -29,10 +29,18 @@ func NewHelpCommand(d *mflags.Dispatcher) *Cmd { return runListCommands(d, opts) } if len(opts.Commands) > 0 { + // If the joined args form a real command path, treat them as one. + // This makes `miren help debug entity list` work the same as + // `miren help debug.entity.list`. + if len(opts.Commands) > 1 && d.HasCommand(strings.Join(opts.Commands, " ")) { + opts.Commands = []string{strings.Join(opts.Commands, " ")} + } return runMultiHelp(d, opts) } - return mflags.ErrShowHelp + RenderTopLevelHelp(d) + return nil }, + WithGroup(GroupClient), WithExample(mflags.Example{ Name: "List all commands", Body: "miren help --commands", diff --git a/cli/commands/help_groups.go b/cli/commands/help_groups.go new file mode 100644 index 000000000..dc478f938 --- /dev/null +++ b/cli/commands/help_groups.go @@ -0,0 +1,27 @@ +package commands + +// Help group constants — used both as the CommandGroup value on registered +// commands and as the display label in help output. +// +// Every top-level command should be tagged with one of these groups. The +// TestAllTopLevelCommandsHaveKnownGroup test catches drift. +const ( + GroupGettingStarted = "Getting started" + GroupMonitoring = "Monitoring your app" + GroupConfiguring = "Configuring your app" + GroupClient = "Client operations" + GroupServer = "Server operations" + + // GroupHidden commands are registered but filtered from help output. + GroupHidden = "Hidden" +) + +// HelpGroupOrder controls the order groups are rendered in top-level help. +// GroupHidden is intentionally absent — commands in that group are filtered. +var HelpGroupOrder = []string{ + GroupGettingStarted, + GroupMonitoring, + GroupConfiguring, + GroupClient, + GroupServer, +} diff --git a/cli/commands/help_groups_test.go b/cli/commands/help_groups_test.go new file mode 100644 index 000000000..80bdb933f --- /dev/null +++ b/cli/commands/help_groups_test.go @@ -0,0 +1,42 @@ +package commands + +import ( + "testing" + + "miren.dev/mflags" + "miren.dev/runtime/pkg/labs" +) + +// TestAllTopLevelCommandsHaveKnownGroup fails if any top-level command is +// missing a CommandGroup or has a CommandGroup not in HelpGroupOrder (or the +// Hidden group). This prevents: +// - Forgetting to tag a new command with WithGroup/WithSectionGroup. +// - Typo'd group strings that would silently create a phantom group. +// - Implicit namespaces at the top level, which cannot carry group metadata +// and should be made explicit with a Section registration. +func TestAllTopLevelCommandsHaveKnownGroup(t *testing.T) { + labs.EnableAll() + + d := mflags.NewDispatcher("miren") + RegisterAll(d) + + known := make(map[string]bool) + for _, g := range HelpGroupOrder { + known[g] = true + } + known[GroupHidden] = true + + for _, child := range d.GetDirectChildren("") { + if !child.IsEntry { + t.Errorf("%q is an implicit namespace — register a parent Section so it can be grouped", child.Name) + continue + } + if child.Group == "" { + t.Errorf("%q has no CommandGroup — tag it with WithGroup/WithSectionGroup", child.Name) + continue + } + if !known[child.Group] { + t.Errorf("%q has group %q which is not in HelpGroupOrder (or GroupHidden)", child.Name, child.Group) + } + } +} diff --git a/cli/commands/help_render.go b/cli/commands/help_render.go new file mode 100644 index 000000000..d1da27e08 --- /dev/null +++ b/cli/commands/help_render.go @@ -0,0 +1,79 @@ +package commands + +import ( + "fmt" + + "github.com/charmbracelet/lipgloss" + "miren.dev/mflags" +) + +// RenderTopLevelHelp renders grouped help output for the top-level command list. +// Commands are rendered in the order defined by HelpGroupOrder. Commands in +// GroupHidden are filtered out. +func RenderTopLevelHelp(d *mflags.Dispatcher) { + children := d.GetDirectChildren("") + + grouped := make(map[string][]mflags.ChildEntry) + for _, child := range children { + if child.Group == GroupHidden { + continue + } + grouped[child.Group] = append(grouped[child.Group], child) + } + + // Compute max name length across rendered commands for column alignment. + maxLen := 0 + for _, group := range HelpGroupOrder { + for _, child := range grouped[group] { + if len(child.Name) > maxLen { + maxLen = len(child.Name) + } + } + } + + headerStyle := lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("220")) + + fmt.Printf("Usage: %s [arguments]\n", d.Name()) + + for _, group := range HelpGroupOrder { + entries := grouped[group] + if len(entries) == 0 { + continue + } + fmt.Println() + fmt.Println(headerStyle.Render(fmt.Sprintf("%s:", group))) + for _, child := range entries { + fmt.Println(formatHelpLine(d, child, maxLen)) + } + } + + fmt.Println() + fmt.Printf("Use '%s help ' or '%s --help' for more information.\n", d.Name(), d.Name()) +} + +// formatHelpLine formats a single command entry for the help listing. +func formatHelpLine(d *mflags.Dispatcher, child mflags.ChildEntry, maxLen int) string { + grandchildren := d.GetDirectChildren(child.Path) + + faint := lipgloss.NewStyle().Faint(true) + + suffix := "" + if len(grandchildren) > 0 { + suffix = " " + faint.Render(subCommandsLabel(len(grandchildren))) + } + + if child.Usage != "" { + return fmt.Sprintf(" %-*s %s%s", maxLen+2, child.Name, child.Usage, suffix) + } + if suffix != "" { + return fmt.Sprintf(" %-*s %s", maxLen+2, child.Name, suffix) + } + return fmt.Sprintf(" %s", child.Name) +} + +func subCommandsLabel(n int) string { + if n == 1 { + return "(1 sub-command)" + } + return fmt.Sprintf("(%d sub-commands)", n) +} diff --git a/cli/commands/infer.go b/cli/commands/infer.go index 14a2a47c1..e0320f26a 100644 --- a/cli/commands/infer.go +++ b/cli/commands/infer.go @@ -26,6 +26,7 @@ type Cmd struct { examples []mflags.Example labsFeature string description string + group string } type CommandOption func(*Cmd) @@ -50,6 +51,13 @@ func WithLabsFeature(feature string) CommandOption { } } +// WithGroup assigns this command to a named group for help rendering. +func WithGroup(group string) CommandOption { + return func(c *Cmd) { + c.group = group + } +} + // Infer creates a command from a function with the signature: // func(ctx *Context, opts StructType) error func Infer(name, syn string, f interface{}, opts ...CommandOption) *Cmd { @@ -127,6 +135,11 @@ func (w *Cmd) Description() string { return w.description } +// CommandGroup implements mflags.CommandGroupProvider. +func (w *Cmd) CommandGroup() string { + return w.group +} + // FlagSet implements mflags.Command func (w *Cmd) FlagSet() *mflags.FlagSet { return w.fs diff --git a/go.mod b/go.mod index 04bfe661d..af690369a 100644 --- a/go.mod +++ b/go.mod @@ -128,7 +128,7 @@ require ( k8s.io/klog/v2 v2.130.1 miren.dev/jsonrpc3/go/jsonrpc3 v0.0.0-20260106052505-c98e2702b093 miren.dev/lbd v0.0.0-20260224020427-8914d8db2233 - miren.dev/mflags v0.0.0-20260313175018-d9ee90a8bb13 + miren.dev/mflags v0.0.0-20260518222642-0ca7adc28461 sigs.k8s.io/knftables v0.0.21 ) diff --git a/go.sum b/go.sum index 01f633004..dab1e0855 100644 --- a/go.sum +++ b/go.sum @@ -1981,8 +1981,12 @@ miren.dev/jsonrpc3/go/jsonrpc3 v0.0.0-20260106052505-c98e2702b093 h1:Sd+M5HSUati miren.dev/jsonrpc3/go/jsonrpc3 v0.0.0-20260106052505-c98e2702b093/go.mod h1:B4A3wSzkcSZQw6Y5opU+rk1+1lEuCWIWkAiN7TkltGE= miren.dev/lbd v0.0.0-20260224020427-8914d8db2233 h1:9DxH7Dhnmu7hn1OA2JC5fHpLuVgAqBySws9GLNssLl4= miren.dev/lbd v0.0.0-20260224020427-8914d8db2233/go.mod h1:+x9fy2p45csBnGUJdqxCUmzlUTCipoVDbv6zIapTgDA= -miren.dev/mflags v0.0.0-20260313175018-d9ee90a8bb13 h1:QPWolXOmZOvh5CBG0i+7QWxBgTzT0nwDlRMHgMpo9P8= -miren.dev/mflags v0.0.0-20260313175018-d9ee90a8bb13/go.mod h1:G1eQ/upWVdO6BGT6dlh5Yqjt+9ncH5RUAKX6UKi1F9Q= +miren.dev/mflags v0.0.0-20260518210420-626d988976a7 h1:s69Bbw35m6rH1j44mVuRet1a5nLlRgfDYoQ1rOCJdGo= +miren.dev/mflags v0.0.0-20260518210420-626d988976a7/go.mod h1:G1eQ/upWVdO6BGT6dlh5Yqjt+9ncH5RUAKX6UKi1F9Q= +miren.dev/mflags v0.0.0-20260518215315-50a3de18904e h1:rGPIp3Og6UrPx5Toi2iudTO+GrzScNeKqpR+HvsoBVI= +miren.dev/mflags v0.0.0-20260518215315-50a3de18904e/go.mod h1:G1eQ/upWVdO6BGT6dlh5Yqjt+9ncH5RUAKX6UKi1F9Q= +miren.dev/mflags v0.0.0-20260518222642-0ca7adc28461 h1:ETSN/0nBy1Dqpu43INesvPWoipOaC5+pfKzRjngkeO0= +miren.dev/mflags v0.0.0-20260518222642-0ca7adc28461/go.mod h1:G1eQ/upWVdO6BGT6dlh5Yqjt+9ncH5RUAKX6UKi1F9Q= modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= From 89c6fb71b032ade8c69b240252bd4be495bc316b Mon Sep 17 00:00:00 2001 From: Paul Hinze Date: Mon, 18 May 2026 17:35:10 -0500 Subject: [PATCH 2/3] Tidy go.sum after mflags pseudo-version bumps --- go.sum | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go.sum b/go.sum index dab1e0855..e85b44b60 100644 --- a/go.sum +++ b/go.sum @@ -1981,10 +1981,6 @@ miren.dev/jsonrpc3/go/jsonrpc3 v0.0.0-20260106052505-c98e2702b093 h1:Sd+M5HSUati miren.dev/jsonrpc3/go/jsonrpc3 v0.0.0-20260106052505-c98e2702b093/go.mod h1:B4A3wSzkcSZQw6Y5opU+rk1+1lEuCWIWkAiN7TkltGE= miren.dev/lbd v0.0.0-20260224020427-8914d8db2233 h1:9DxH7Dhnmu7hn1OA2JC5fHpLuVgAqBySws9GLNssLl4= miren.dev/lbd v0.0.0-20260224020427-8914d8db2233/go.mod h1:+x9fy2p45csBnGUJdqxCUmzlUTCipoVDbv6zIapTgDA= -miren.dev/mflags v0.0.0-20260518210420-626d988976a7 h1:s69Bbw35m6rH1j44mVuRet1a5nLlRgfDYoQ1rOCJdGo= -miren.dev/mflags v0.0.0-20260518210420-626d988976a7/go.mod h1:G1eQ/upWVdO6BGT6dlh5Yqjt+9ncH5RUAKX6UKi1F9Q= -miren.dev/mflags v0.0.0-20260518215315-50a3de18904e h1:rGPIp3Og6UrPx5Toi2iudTO+GrzScNeKqpR+HvsoBVI= -miren.dev/mflags v0.0.0-20260518215315-50a3de18904e/go.mod h1:G1eQ/upWVdO6BGT6dlh5Yqjt+9ncH5RUAKX6UKi1F9Q= miren.dev/mflags v0.0.0-20260518222642-0ca7adc28461 h1:ETSN/0nBy1Dqpu43INesvPWoipOaC5+pfKzRjngkeO0= miren.dev/mflags v0.0.0-20260518222642-0ca7adc28461/go.mod h1:G1eQ/upWVdO6BGT6dlh5Yqjt+9ncH5RUAKX6UKi1F9Q= modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= From e39c952578b4d962e9ded512aa7adc063f980e0d Mon Sep 17 00:00:00 2001 From: Paul Hinze Date: Mon, 18 May 2026 17:40:36 -0500 Subject: [PATCH 3/3] Regenerate command docs for grouping changes --- docs/command-sidebar.json | 13 +------------ docs/docs/command/alias.md | 4 ++-- docs/docs/command/disk.md | 4 ++-- docs/docs/command/help-alias.md | 25 ------------------------- docs/docs/command/help.md | 4 ---- docs/docs/commands.md | 5 ++--- 6 files changed, 7 insertions(+), 48 deletions(-) delete mode 100644 docs/docs/command/help-alias.md diff --git a/docs/command-sidebar.json b/docs/command-sidebar.json index c401e772a..34c0c20a3 100644 --- a/docs/command-sidebar.json +++ b/docs/command-sidebar.json @@ -214,18 +214,7 @@ "command/env-set" ] }, - { - "type": "category", - "label": "help", - "collapsed": true, - "link": { - "type": "doc", - "id": "command/help" - }, - "items": [ - "command/help-alias" - ] - }, + "command/help", "command/init", "command/login", "command/logout", diff --git a/docs/docs/command/alias.md b/docs/docs/command/alias.md index afb7e95d9..6b9b7fab1 100644 --- a/docs/docs/command/alias.md +++ b/docs/docs/command/alias.md @@ -1,12 +1,12 @@ --- title: "miren alias" sidebar_label: "alias" -description: "" +description: "CLI alias management" --- # miren alias - +CLI alias management ## Usage diff --git a/docs/docs/command/disk.md b/docs/docs/command/disk.md index f355db5fa..f66c5d485 100644 --- a/docs/docs/command/disk.md +++ b/docs/docs/command/disk.md @@ -1,12 +1,12 @@ --- title: "miren disk" sidebar_label: "disk" -description: "" +description: "Disk backup and recovery" --- # miren disk - +Disk backup and recovery ## Usage diff --git a/docs/docs/command/help-alias.md b/docs/docs/command/help-alias.md deleted file mode 100644 index f88bba5e0..000000000 --- a/docs/docs/command/help-alias.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "miren help alias" -sidebar_label: "help alias" -description: "Learn how to define and use CLI aliases" ---- - -# miren help alias - -Learn how to define and use CLI aliases - -## Usage - -```bash -miren help alias [flags] -``` - -## Global Options - -- `--options` — Path to file containing options -- `--server-address` — Server address to connect to (default: `127.0.0.1:8443`) -- `--verbose, -v` — Enable verbose output - -## See also - -- [`miren help`](/command/help) diff --git a/docs/docs/command/help.md b/docs/docs/command/help.md index 651527427..3d3e7b87d 100644 --- a/docs/docs/command/help.md +++ b/docs/docs/command/help.md @@ -45,7 +45,3 @@ miren help --commands --format json ```bash miren help app.list version sandbox.stop ``` - -## Subcommands - -- [`miren help alias`](/command/help-alias) — Learn how to define and use CLI aliases diff --git a/docs/docs/commands.md b/docs/docs/commands.md index 8ea1c176a..4f778c9e2 100644 --- a/docs/docs/commands.md +++ b/docs/docs/commands.md @@ -29,7 +29,7 @@ Complete reference for all `miren` CLI commands. | Command | Description | |---------|-------------| -| [`miren alias`](/command/alias) | | +| [`miren alias`](/command/alias) | CLI alias management | | [`miren alias list`](/command/alias-list) | List configured CLI aliases | ## app @@ -98,7 +98,7 @@ Complete reference for all `miren` CLI commands. | Command | Description | |---------|-------------| -| [`miren disk`](/command/disk) | | +| [`miren disk`](/command/disk) | Disk backup and recovery | | [`miren disk backup`](/command/disk-backup) | Backup a disk to a snapshot file | | [`miren disk list-deleted`](/command/disk-list-deleted) | List deleted disks available for recovery | | [`miren disk restore`](/command/disk-restore) | Restore a disk from a snapshot file | @@ -135,7 +135,6 @@ Complete reference for all `miren` CLI commands. | Command | Description | |---------|-------------| | [`miren help`](/command/help) | Show help for one or more commands | -| [`miren help alias`](/command/help-alias) | Learn how to define and use CLI aliases | ## init