@@ -11,9 +11,11 @@ import (
1111 "sort"
1212 "strings"
1313
14+ "github.com/larksuite/cli/cmd/service"
1415 "github.com/larksuite/cli/errs"
1516 "github.com/larksuite/cli/extension/platform"
1617 "github.com/larksuite/cli/internal/build"
18+ "github.com/larksuite/cli/internal/cmdmeta"
1719 "github.com/larksuite/cli/internal/cmdpolicy"
1820 "github.com/larksuite/cli/internal/cmdutil"
1921 "github.com/larksuite/cli/internal/deprecation"
@@ -28,43 +30,60 @@ import (
2830
2931const rootLong = `lark-cli — Lark/Feishu CLI tool.
3032
31- USAGE:
32- lark-cli <command> [subcommand] [method] [options]
33- lark-cli api <method> <path> [--params <json>] [--data <json>]
34- lark-cli schema <service.resource.method>
33+ AGENT QUICKSTART (driving this as an agent? start here):
34+ Browse commands: lark-cli <domain> --help # +shortcuts (preferred) and raw API resources
35+ Inspect a call: lark-cli schema <service>.<resource>.<method> # params, types, scopes, examples
36+ Prefer a +shortcut over the raw API resource when one matches the task.
37+ Risk: each command's --help shows read | write | high-risk-write;
38+ high-risk-write needs --yes, only after the user confirms.
39+ On any API call: --jq <expr> filters JSON output, --dry-run previews the request (runs nothing).
3540
36- EXAMPLES:
37- # View upcoming events
38- lark-cli calendar +agenda
41+ EXAMPLES (one per command style, in order of preference):
42+ lark-cli calendar +agenda # +shortcut — a high-level task, prefer these
43+ lark-cli mail user_mailbox.messages list --user-mailbox-id me # typed command for one API method
44+ lark-cli schema mail.user_mailbox.messages.list # inspect a method's params before calling
45+ lark-cli api GET /open-apis/calendar/v4/calendars # raw escape hatch — any endpoint by HTTP path`
3946
40- # List calendar events
41- lark-cli calendar events instance_view --params '{"calendar_id":"primary","start_time":"1700000000","end_time":"1700086400"}'
47+ // rootUsageTemplate is cobra's default usage template with two root-only
48+ // additions gated on {{if not .HasParent}}: a curated multi-form Usage synopsis
49+ // (replacing cobra's generic "[flags] / [command]") and a human skills-setup
50+ // footer. Subcommands render the stock template unchanged. The rest is verbatim
51+ // cobra so the command groups and flags are untouched.
52+ const rootUsageTemplate = `{{if .HasParent}}Usage:{{if .Runnable}}
53+ {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
54+ {{.CommandPath}} [command]{{end}}{{else}}Usage:
55+ lark-cli <command> [subcommand] [method] [flags]
56+ lark-cli api <method> <path> [--params <json>] [--data <json>]
57+ lark-cli schema <service.resource.method>{{end}}{{if gt (len .Aliases) 0}}
4258
43- # Search users
44- lark-cli contact +search-user --query "John"
59+ Aliases:
60+ {{.NameAndAliases}}{{end}}{{if .HasExample}}
4561
46- # Generic API call
47- lark-cli api GET /open-apis/calendar/v4/calendars
62+ Examples:
63+ {{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}}
4864
49- AI AGENT SKILLS:
50- lark-cli pairs with AI agent skills (Claude Code, etc.) that
51- teach the agent Lark API patterns, best practices, and workflows.
65+ Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
66+ {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}}
5267
53- Install all skills:
54- npx skills add larksuite/cli -g -y
68+ {{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}}
69+ {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}}
5570
56- Or pick specific domains:
57- npx skills add larksuite/cli -s lark-calendar -y
58- npx skills add larksuite/cli -s lark-im -y
71+ Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}}
72+ {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
5973
60- Learn more: https://github.com/larksuite/cli#agent-skills
74+ Flags:
75+ {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
6176
62- COMMUNITY:
63- GitHub: https://github.com/larksuite/cli
64- Issues: https://github.com/larksuite/cli/issues
65- Docs: https://open.feishu.cn/document/
77+ Global Flags:
78+ {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
6679
67- More help: lark-cli <command> --help`
80+ Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
81+ {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
82+
83+ Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}{{if not .HasParent}}
84+
85+ Skills setup (one-time, humans): npx skills add larksuite/cli -g -y — https://github.com/larksuite/cli#agent-skills{{end}}
86+ `
6887
6988// Execute runs the root command and returns the process exit code.
7089// rawInvocationArgs holds os.Args[1:] captured at Execute() entry. cobra's
@@ -529,6 +548,49 @@ func availableSubcommandNames(cmd *cobra.Command) (available, deprecated []strin
529548 return available , deprecated
530549}
531550
551+ // Root command help groups, so an agent sees content domains, agent tooling, and
552+ // CLI management as distinct blocks instead of one flat alphabetical dump.
553+ const (
554+ groupDomains = "lark-domains"
555+ groupTooling = "agent-tooling"
556+ groupManagement = "cli-management"
557+ )
558+
559+ // groupRootCommands classifies root's direct children into the help groups,
560+ // called once after all commands are registered. Unclassified commands fall to
561+ // cobra's "Additional Commands" section.
562+ func groupRootCommands (root * cobra.Command ) {
563+ root .AddGroup (
564+ & cobra.Group {ID : groupDomains , Title : "Lark domains:" },
565+ & cobra.Group {ID : groupTooling , Title : "Agent tooling:" },
566+ & cobra.Group {ID : groupManagement , Title : "CLI management:" },
567+ )
568+ tooling := map [string ]bool {"api" : true , "schema" : true , "skills" : true }
569+ management := map [string ]bool {"auth" : true , "config" : true , "profile" : true , "doctor" : true , "update" : true }
570+ for _ , c := range root .Commands () {
571+ if c .GroupID != "" {
572+ continue
573+ }
574+ switch {
575+ case tooling [c .Name ()]:
576+ c .GroupID = groupTooling
577+ case management [c .Name ()]:
578+ c .GroupID = groupManagement
579+ case isLarkDomain (c ):
580+ c .GroupID = groupDomains
581+ }
582+ }
583+ }
584+
585+ // isLarkDomain reports whether a root child is a Lark domain (service-sourced or
586+ // shortcut-tagged), not CLI tooling. Mirrors service.PrepareDomainHelp.
587+ func isLarkDomain (c * cobra.Command ) bool {
588+ if src , _ := cmdmeta .SourceOf (c ); src == cmdmeta .SourceService {
589+ return true
590+ }
591+ return cmdmeta .Domain (c ) != ""
592+ }
593+
532594// flagDidYouMean is the root FlagErrorFunc (inherited by all subcommands). It
533595// converts cobra's flag-parse errors into a typed validation envelope: an
534596// unknown flag gets a focused "did you mean" hint (so agents recover even when
@@ -610,6 +672,17 @@ func installTipsHelpFunc(root *cobra.Command) {
610672 defer func () { f .Hidden = true }()
611673 }
612674 }
675+ // Domain and method commands compose their agent guidance into Long lazily
676+ // here (shortcuts attach after service registration); both skip the generic
677+ // bottom-of-help append below.
678+ if service .PrepareDomainHelp (cmd , embeddedSkillContent ) {
679+ defaultHelp (cmd , args )
680+ return
681+ }
682+ if service .PrepareMethodHelp (cmd ) {
683+ defaultHelp (cmd , args )
684+ return
685+ }
613686 defaultHelp (cmd , args )
614687 out := cmd .OutOrStdout ()
615688 if level , ok := cmdutil .GetRisk (cmd ); ok {
0 commit comments