Compare commits

...

1 Commits

Author SHA1 Message Date
Devv
9246517288 refactor(cli): adopt gh-style help output with grouped commands
Replaces Cobra's default help templates with custom gh-style formatting:
- UPPERCASE section headers (USAGE, CORE COMMANDS, FLAGS, etc.)
- Commands grouped into CORE, RUNTIME, and ADDITIONAL categories
- Subcommands grouped into GENERAL and TARGETED categories
- Colon-separated format with aligned descriptions
- EXAMPLES, ENVIRONMENT VARIABLES, and LEARN MORE sections
- Consistent help style across root, group, and leaf commands

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 14:57:11 -07:00
9 changed files with 284 additions and 9 deletions

View File

@@ -15,7 +15,7 @@ import (
var agentCmd = &cobra.Command{
Use: "agent",
Short: "Manage agents",
Short: "Work with agents",
}
var agentListCmd = &cobra.Command{

View File

@@ -22,7 +22,7 @@ import (
var authCmd = &cobra.Command{
Use: "auth",
Short: "Manage authentication",
Short: "Authenticate multica with Multica",
}
var authLoginCmd = &cobra.Command{

View File

@@ -11,7 +11,7 @@ import (
var configCmd = &cobra.Command{
Use: "config",
Short: "Show CLI configuration",
Short: "Manage configuration for multica",
RunE: runConfigShow,
}

View File

@@ -23,7 +23,7 @@ import (
var daemonCmd = &cobra.Command{
Use: "daemon",
Short: "Manage the local agent runtime daemon",
Short: "Manage the local agent runtime",
}
var daemonStartCmd = &cobra.Command{

View File

@@ -16,7 +16,8 @@ import (
var issueCmd = &cobra.Command{
Use: "issue",
Short: "Manage issues",
Short: "Work with issues",
Long: "Work with Multica issues.",
}
var issueListCmd = &cobra.Command{
@@ -63,7 +64,7 @@ var issueStatusCmd = &cobra.Command{
var issueCommentCmd = &cobra.Command{
Use: "comment",
Short: "Manage issue comments",
Short: "Work with issue comments",
}
var issueCommentListCmd = &cobra.Command{
@@ -108,6 +109,19 @@ var validIssueStatuses = []string{
}
func init() {
// General commands — listing and creation.
setGroup(issueListCmd, groupCore)
setGroup(issueCreateCmd, groupCore)
setGroup(issueGetCmd, groupCore)
// Targeted commands — operate on specific issues.
setGroup(issueUpdateCmd, groupAdditional)
setGroup(issueAssignCmd, groupAdditional)
setGroup(issueStatusCmd, groupAdditional)
setGroup(issueCommentCmd, groupAdditional)
setGroup(issueRunsCmd, groupAdditional)
setGroup(issueRunMessagesCmd, groupAdditional)
issueCmd.AddCommand(issueListCmd)
issueCmd.AddCommand(issueGetCmd)
issueCmd.AddCommand(issueCreateCmd)

View File

@@ -14,7 +14,7 @@ import (
var repoCmd = &cobra.Command{
Use: "repo",
Short: "Manage repositories",
Short: "Work with repositories",
}
var repoCheckoutCmd = &cobra.Command{

View File

@@ -15,7 +15,7 @@ import (
var workspaceCmd = &cobra.Command{
Use: "workspace",
Short: "Manage workspaces",
Short: "Work with workspaces",
}
var workspaceListCmd = &cobra.Command{

241
server/cmd/multica/help.go Normal file
View File

@@ -0,0 +1,241 @@
package main
import (
"fmt"
"strings"
"github.com/spf13/cobra"
)
// Command group annotation key.
const cmdGroupKey = "group"
// Group names used to categorize commands in help output.
const (
groupCore = "core"
groupRuntime = "runtime"
groupAdditional = "additional"
)
// setGroup annotates a command with a help group.
func setGroup(cmd *cobra.Command, group string) {
if cmd.Annotations == nil {
cmd.Annotations = map[string]string{}
}
cmd.Annotations[cmdGroupKey] = group
}
// commandsByGroup collects visible subcommands by group name.
// Commands without an annotation go into "additional".
func commandsByGroup(cmd *cobra.Command) map[string][]*cobra.Command {
groups := map[string][]*cobra.Command{}
for _, c := range cmd.Commands() {
if c.Hidden || c.Name() == "help" || c.Name() == "completion" {
continue
}
g := groupAdditional
if v, ok := c.Annotations[cmdGroupKey]; ok {
g = v
}
groups[g] = append(groups[g], c)
}
return groups
}
// formatCommandList renders a list of commands in gh style:
//
// name: description
func formatCommandList(cmds []*cobra.Command) string {
if len(cmds) == 0 {
return ""
}
// Find max command name length for alignment.
maxLen := 0
for _, c := range cmds {
if len(c.Name()) > maxLen {
maxLen = len(c.Name())
}
}
var b strings.Builder
for _, c := range cmds {
padding := strings.Repeat(" ", maxLen-len(c.Name()))
fmt.Fprintf(&b, " %s:%s %s\n", c.Name(), padding, c.Short)
}
return b.String()
}
// rootHelpFunc returns a custom help function for the root command (gh style).
func rootHelpFunc(cmd *cobra.Command, _ []string) {
groups := commandsByGroup(cmd)
fmt.Println(cmd.Long)
fmt.Println()
fmt.Println("USAGE")
fmt.Printf(" %s <command> <subcommand> [flags]\n", cmd.Name())
fmt.Println()
// Print command groups in order.
type section struct {
title string
key string
}
sections := []section{
{"CORE COMMANDS", groupCore},
{"RUNTIME COMMANDS", groupRuntime},
{"ADDITIONAL COMMANDS", groupAdditional},
}
for _, s := range sections {
cmds := groups[s.key]
if len(cmds) == 0 {
continue
}
fmt.Println(s.title)
fmt.Print(formatCommandList(cmds))
fmt.Println()
}
fmt.Println("FLAGS")
fmt.Println(" --help Show help for command")
fmt.Println(" --version Show multica version")
fmt.Println()
fmt.Println("ENVIRONMENT VARIABLES")
fmt.Println(" MULTICA_SERVER_URL Multica server URL")
fmt.Println(" MULTICA_WORKSPACE_ID Default workspace ID")
fmt.Println(" MULTICA_TOKEN Authentication token")
fmt.Println()
fmt.Println("EXAMPLES")
fmt.Println(" $ multica login")
fmt.Println(" $ multica issue list --status todo")
fmt.Println(" $ multica daemon start")
fmt.Println()
fmt.Println("LEARN MORE")
fmt.Printf(" Use `%s <command> <subcommand> --help` for more information about a command.\n", cmd.Name())
fmt.Println(" Read the documentation at https://multica.ai/docs")
}
// subcommandHelpFunc returns a custom help function for group commands (issue, agent, etc.)
func subcommandHelpFunc(cmd *cobra.Command, _ []string) {
groups := commandsByGroup(cmd)
// Print description.
if cmd.Long != "" {
fmt.Println(cmd.Long)
} else {
fmt.Println(cmd.Short)
}
fmt.Println()
// Usage line.
fmt.Println("USAGE")
fmt.Printf(" %s %s <command> [flags]\n", cmd.Root().Name(), cmd.Name())
fmt.Println()
// Print grouped subcommands.
type section struct {
title string
key string
}
sections := []section{
{"GENERAL COMMANDS", groupCore},
{"TARGETED COMMANDS", groupAdditional},
}
// If no groups are annotated, print all as COMMANDS.
hasGroups := false
for _, s := range sections {
if len(groups[s.key]) > 0 && s.key != groupAdditional {
hasGroups = true
break
}
}
if !hasGroups {
// No group annotations — print flat list.
var all []*cobra.Command
for _, cmds := range groups {
all = append(all, cmds...)
}
if len(all) > 0 {
fmt.Println("COMMANDS")
fmt.Print(formatCommandList(all))
fmt.Println()
}
} else {
for _, s := range sections {
cmds := groups[s.key]
if len(cmds) == 0 {
continue
}
fmt.Println(s.title)
fmt.Print(formatCommandList(cmds))
fmt.Println()
}
}
// Flags.
localFlags := cmd.LocalNonPersistentFlags()
if localFlags.HasFlags() {
fmt.Println("FLAGS")
fmt.Println(localFlags.FlagUsages())
}
fmt.Println("INHERITED FLAGS")
fmt.Println(" --help Show help for command")
fmt.Println()
fmt.Println("LEARN MORE")
fmt.Printf(" Use `%s %s <command> --help` for more information about a command.\n", cmd.Root().Name(), cmd.Name())
}
// leafHelpFunc provides gh-style help for leaf commands (commands with RunE/Run).
func leafHelpFunc(cmd *cobra.Command, _ []string) {
// Build full command path.
path := cmd.CommandPath()
// Description.
if cmd.Long != "" {
fmt.Println(cmd.Long)
} else {
fmt.Println(cmd.Short)
}
fmt.Println()
// Usage.
fmt.Println("USAGE")
fmt.Printf(" %s [flags]\n", path)
fmt.Println()
// Local flags.
localFlags := cmd.LocalNonPersistentFlags()
if localFlags.HasFlags() {
fmt.Println("FLAGS")
fmt.Print(localFlags.FlagUsages())
fmt.Println()
}
// Inherited flags.
fmt.Println("INHERITED FLAGS")
fmt.Println(" --help Show help for command")
fmt.Println()
fmt.Println("LEARN MORE")
fmt.Printf(" Use `%s <command> --help` for more information about a command.\n", cmd.Root().Name())
}
// applyHelpFuncs recursively sets the appropriate help function on all commands.
func applyHelpFuncs(cmd *cobra.Command) {
for _, c := range cmd.Commands() {
if c.HasSubCommands() {
c.SetHelpFunc(subcommandHelpFunc)
} else if c.Run != nil || c.RunE != nil {
c.SetHelpFunc(leafHelpFunc)
}
applyHelpFuncs(c)
}
}

View File

@@ -15,7 +15,7 @@ var (
var rootCmd = &cobra.Command{
Use: "multica",
Short: "Multica CLI — local agent runtime and management tool",
Long: "multica manages local agent runtimes and provides control commands for the Multica platform.",
Long: "Work seamlessly with Multica from the command line.",
SilenceUsage: true,
SilenceErrors: true,
}
@@ -25,6 +25,22 @@ func init() {
rootCmd.PersistentFlags().String("workspace-id", "", "Workspace ID (env: MULTICA_WORKSPACE_ID)")
rootCmd.PersistentFlags().String("profile", "", "Configuration profile name (e.g. dev) — isolates config, daemon state, and workspaces")
// Core commands — primary task management.
setGroup(issueCmd, groupCore)
setGroup(agentCmd, groupCore)
setGroup(workspaceCmd, groupCore)
// Runtime commands — agent execution.
setGroup(daemonCmd, groupRuntime)
// Additional commands (default group for the rest).
setGroup(loginCmd, groupAdditional)
setGroup(authCmd, groupAdditional)
setGroup(configCmd, groupAdditional)
setGroup(repoCmd, groupAdditional)
setGroup(updateCmd, groupAdditional)
setGroup(versionCmd, groupAdditional)
rootCmd.AddCommand(loginCmd)
rootCmd.AddCommand(authCmd)
rootCmd.AddCommand(daemonCmd)
@@ -35,6 +51,10 @@ func init() {
rootCmd.AddCommand(repoCmd)
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(updateCmd)
// Apply gh-style help templates.
rootCmd.SetHelpFunc(rootHelpFunc)
applyHelpFuncs(rootCmd)
}
func main() {