← back to Cli Printing Press
feat(cli): hide raw resource commands when promoted exist, add api discovery (#121)
4b12b325c3de463d80092d0768b090af1d13faac · 2026-04-04 10:38:53 -0700 · Trevin Chow
When the generator produces promoted commands (user-friendly aliases),
raw resource parent commands are now hidden from --help but remain
fully functional. An `api` discovery command is auto-generated to let
agents and power users browse hidden interfaces.
Machine changes:
- command_parent.go.tmpl: accepts Hidden bool, sets Hidden: true in cobra
- api_discovery.go.tmpl: NEW template for the api browsing command
- generator.go: computes promotedCommands early, sets Hidden on parents,
renders api_discovery.go when promoted commands exist
- Removed resourceGroupNames self-collision check from buildPromotedCommands
(was preventing all promoted commands from being generated)
The gate is simple: len(promotedCommands) > 0. APIs with clean resource
names (links, domains, tags) get clean help. APIs without promotable
endpoints show resource parents as before.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Files touched
A docs/plans/2026-04-04-001-feat-hide-raw-commands-api-discovery-plan.mdM internal/generator/generator.goM internal/generator/generator_test.goA internal/generator/templates/api_discovery.go.tmplM internal/generator/templates/command_parent.go.tmplM internal/generator/templates/root.go.tmpl
Diff
commit 4b12b325c3de463d80092d0768b090af1d13faac
Author: Trevin Chow <trevin@trevinchow.com>
Date: Sat Apr 4 10:38:53 2026 -0700
feat(cli): hide raw resource commands when promoted exist, add api discovery (#121)
When the generator produces promoted commands (user-friendly aliases),
raw resource parent commands are now hidden from --help but remain
fully functional. An `api` discovery command is auto-generated to let
agents and power users browse hidden interfaces.
Machine changes:
- command_parent.go.tmpl: accepts Hidden bool, sets Hidden: true in cobra
- api_discovery.go.tmpl: NEW template for the api browsing command
- generator.go: computes promotedCommands early, sets Hidden on parents,
renders api_discovery.go when promoted commands exist
- Removed resourceGroupNames self-collision check from buildPromotedCommands
(was preventing all promoted commands from being generated)
The gate is simple: len(promotedCommands) > 0. APIs with clean resource
names (links, domains, tags) get clean help. APIs without promotable
endpoints show resource parents as before.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
...01-feat-hide-raw-commands-api-discovery-plan.md | 165 +++++++++++++++++++++
internal/generator/generator.go | 54 ++++---
internal/generator/generator_test.go | 43 +++---
internal/generator/templates/api_discovery.go.tmpl | 76 ++++++++++
.../generator/templates/command_parent.go.tmpl | 3 +
internal/generator/templates/root.go.tmpl | 7 +-
6 files changed, 310 insertions(+), 38 deletions(-)
diff --git a/docs/plans/2026-04-04-001-feat-hide-raw-commands-api-discovery-plan.md b/docs/plans/2026-04-04-001-feat-hide-raw-commands-api-discovery-plan.md
new file mode 100644
index 00000000..93f9ec0e
--- /dev/null
+++ b/docs/plans/2026-04-04-001-feat-hide-raw-commands-api-discovery-plan.md
@@ -0,0 +1,165 @@
+---
+title: "feat: Hide raw resource commands when promoted commands exist, add api discovery"
+type: feat
+status: active
+date: 2026-04-04
+---
+
+# Hide Raw Resource Commands + Add API Discovery
+
+## Overview
+
+When the generator produces promoted commands (friendly top-level aliases like `resolve`, `profile`, `games`), the raw resource parent commands (`isteam-user`, `iplayer-service`) should be hidden from `--help` but remain functional. An `api` discovery command should be auto-generated to let agents and power users browse hidden interfaces.
+
+This is conditional: CLIs without promoted commands show resource parents as usual (they ARE the user interface). The `api` command is only generated when there are hidden commands to discover.
+
+## Problem Frame
+
+The generator creates promoted commands (friendly aliases) alongside the original resource parent commands. Both appear in `--help`, creating a noisy, confusing listing where `isteam-user get-player-summaries` sits next to `profile`. Users don't know which to use. Agents parsing `--help` get duplicate functionality.
+
+The Steam CLI proved the pattern: hide raw commands with `Hidden: true`, add an `api` command for discovery. This plan makes it a machine change so every future CLI benefits.
+
+## Requirements Trace
+
+- R1. Resource parent commands set `Hidden: true` when the CLI has promoted commands
+- R2. Resource parent commands remain visible when no promoted commands exist
+- R3. An `api` discovery command is generated when promoted commands exist, listing all hidden interfaces and their methods
+- R4. The `api` command is NOT generated when there are no promoted commands (nothing to discover)
+- R5. Hidden commands remain fully functional — only hidden from `--help` output
+
+## Scope Boundaries
+
+- **Not changing promoted command generation logic.** `buildPromotedCommands()` is unchanged.
+- **Not changing which commands get promoted.** The selection criteria stay the same.
+- **Not adding manual promoted command configuration.** The Phase 3 agent-built commands (like Steam's `resolve`, `profile`) are printed-CLI work, not machine work. This plan handles the machine's auto-generated promoted commands only.
+
+## Key Technical Decisions
+
+- **Use `len(.PromotedCommands) > 0` as the gate**: The root template data already has `.PromotedCommands`. If the slice is non-empty, hide resource parents and add `api`. If empty, no change from today. No new flags or configuration needed.
+
+- **`Hidden` field on command_parent.go.tmpl**: Add a `Hidden bool` to the parent command template data struct. Set it to `true` when promoted commands exist. The template emits `Hidden: true,` in the cobra.Command struct.
+
+- **`api_discovery.go.tmpl` as a new template**: A standalone template (not vision-gated) rendered only when promoted commands exist. It creates the `api` command that lists hidden interface commands and drills into their methods.
+
+## Implementation Units
+
+- [ ] **Unit 1: Add `Hidden` field to resource parent template**
+
+**Goal:** Resource parent commands set `Hidden: true` when promoted commands exist.
+
+**Requirements:** R1, R2, R5
+
+**Dependencies:** None
+
+**Files:**
+- Modify: `internal/generator/templates/command_parent.go.tmpl`
+- Modify: `internal/generator/generator.go` (add `Hidden bool` to parent template data struct)
+- Test: `internal/generator/generator_test.go`
+
+**Approach:**
+- Add `Hidden bool` to the parent command template data struct in `generator.go` (around line 310)
+- Set `Hidden: len(promotedCommands) > 0` — but `promotedCommands` is computed after resource rendering. Solution: compute promoted commands earlier (before the resource rendering loop), or pass the count through a different path. Since we already moved profiling early (for HasStore), we can compute `promotedCommands` before the resource loop too.
+- In `command_parent.go.tmpl`, add `{{if .Hidden}}Hidden: true,{{end}}` after the `Short:` field
+
+**Patterns to follow:**
+- Existing `HasStore bool` field on endpoint template data (same pattern — generator sets, template uses)
+- Existing `Hidden: true` pattern in cobra (standard cobra field)
+
+**Test scenarios:**
+- Happy path: spec with promoted commands (e.g., clerk) → resource parent commands have `Hidden: true` in generated code
+- Happy path: spec without promoted commands (e.g., petstore with few resources) → resource parent commands do NOT have `Hidden: true`
+- Integration: generate a CLI with promoted commands → `--help` shows promoted commands, hides resource parents
+- Edge case: resource parent with no promotable endpoint → still hidden if OTHER resources have promoted commands (the gate is global, not per-resource)
+
+**Verification:**
+- Generated CLI with promoted commands shows clean `--help` without raw interface names
+- Generated CLI without promoted commands shows resource parents as before
+
+---
+
+- [ ] **Unit 2: Create `api_discovery.go.tmpl`**
+
+**Goal:** Auto-generate an `api` command that lists hidden interfaces and their methods.
+
+**Requirements:** R3, R4
+
+**Dependencies:** Unit 1
+
+**Files:**
+- Create: `internal/generator/templates/api_discovery.go.tmpl`
+- Modify: `internal/generator/generator.go` (render the template conditionally when promoted commands exist)
+- Test: `internal/generator/generator_test.go`
+
+**Approach:**
+- Create `api_discovery.go.tmpl` in the `cli` package. It generates a command that:
+ - With no args: lists all `Hidden` commands on the root, with name and Short description
+ - With one arg (interface name): lists that interface's subcommands (methods)
+ - Includes realistic examples in the help text
+- In `generator.go`, render `api_discovery.go.tmpl` only when `len(promotedCommands) > 0`. Place the render after promoted commands are computed but before `root.go.tmpl` is rendered (so the template can reference the api command constructor).
+- Register `newAPICmd` in `root.go.tmpl` conditionally: `{{if .PromotedCommands}}rootCmd.AddCommand(newAPICmd(&flags)){{end}}`
+
+**Patterns to follow:**
+- The `cmd_api.go` file we manually built for Steam — use it as the reference implementation
+- Existing conditional command registration in `root.go.tmpl` (e.g., `{{if .VisionSet.Search}}`)
+
+**Test scenarios:**
+- Happy path: generate a CLI with promoted commands → `api` command exists, lists hidden interfaces
+- Happy path: generate a CLI without promoted commands → no `api` command, no `api_discovery.go` file
+- Happy path: `api <interface>` shows methods for that interface
+- Edge case: `api nonexistent` returns a clear error
+- Integration: generated CLI compiles with `api` command, `--help` shows it alongside promoted commands
+
+**Verification:**
+- Generated CLI with promoted commands has `api` in `--help`
+- `api` lists all hidden interfaces
+- `api <interface>` shows methods
+- Generated CLI without promoted commands does NOT have `api`
+
+---
+
+- [ ] **Unit 3: Update root.go.tmpl registration and file count test**
+
+**Goal:** Register `api` command conditionally and update expected file counts.
+
+**Requirements:** R3, R4
+
+**Dependencies:** Unit 1, Unit 2
+
+**Files:**
+- Modify: `internal/generator/templates/root.go.tmpl`
+- Modify: `internal/generator/generator_test.go` (update expected file counts for specs that get promoted commands)
+
+**Approach:**
+- Add `{{if .PromotedCommands}}rootCmd.AddCommand(newAPICmd(&flags)){{end}}` before the promoted commands registration block
+- Update expected file counts in `TestGenerateProjectsCompile` — specs with promoted commands get +1 file (api_discovery.go)
+
+**Test scenarios:**
+- Happy path: all existing test specs compile with updated file counts
+- Happy path: petstore (no promoted commands) → no api_discovery.go, file count unchanged
+- Happy path: clerk/loops (with promoted commands) → api_discovery.go generated, file count +1
+
+**Verification:**
+- `go test ./internal/generator/...` passes
+- `go test ./...` passes (1055+ tests)
+
+## System-Wide Impact
+
+- **`--help` output changes for CLIs with promoted commands**: Resource parent commands disappear from `--help`. This is the intended behavior — the promoted commands are the user-facing interface. Hidden commands remain functional.
+- **No change for CLIs without promoted commands**: Petstore-class CLIs with few resources and no promotable endpoints show resource parents exactly as before.
+- **Scorecard unaffected**: The scorecard checks command count, help output, etc. — hidden commands still count as commands. The `api` command adds one more visible command.
+- **Verify unaffected**: Verify discovers commands from both `--help` and root.go parsing. Hidden commands are still testable.
+
+## Risks & Dependencies
+
+| Risk | Mitigation |
+|------|------------|
+| Promoted commands may not cover all important operations | The `api` command provides full access to hidden interfaces. Power users and agents can discover and use any endpoint. |
+| Breaking change for existing CLIs that regenerate | `--help` output changes. This is intentional and desirable — the old help was noisy. No functional behavior changes. |
+| `buildPromotedCommands()` may produce poor aliases for some APIs | Not in scope — the selection criteria are unchanged. The skill's Phase 3 is where the agent makes product decisions about command naming. |
+
+## Sources & References
+
+- Reference implementation: `steam-web-pp-cli/internal/cli/cmd_api.go` (manually built)
+- Related code: `internal/generator/generator.go` (buildPromotedCommands, root template data)
+- Related code: `internal/generator/templates/command_parent.go.tmpl` (resource parent template)
+- Related code: `internal/generator/templates/root.go.tmpl` (command registration)
diff --git a/internal/generator/generator.go b/internal/generator/generator.go
index 8aa839e8..6859320e 100644
--- a/internal/generator/generator.go
+++ b/internal/generator/generator.go
@@ -301,21 +301,28 @@ func (g *Generator) Generate() error {
}
}
+ // Compute promoted commands early — needed to determine Hidden flag on parent commands
+ promotedCommands := buildPromotedCommands(g.Spec)
+ hasPromoted := len(promotedCommands) > 0
+
// Generate per-resource parent files + per-endpoint command files
// This produces more files (one per endpoint) which improves Breadth scoring
for name, resource := range g.Spec.Resources {
// Parent file: wires subcommands together
+ // When promoted commands exist, hide resource parents from --help
parentData := struct {
ResourceName string
FuncPrefix string
CommandPath string
Resource spec.Resource
+ Hidden bool
*spec.APISpec
}{
ResourceName: name,
FuncPrefix: name,
CommandPath: name,
Resource: resource,
+ Hidden: hasPromoted,
APISpec: g.Spec,
}
parentPath := filepath.Join("internal", "cli", name+".go")
@@ -355,12 +362,14 @@ func (g *Generator) Generate() error {
FuncPrefix string
CommandPath string
Resource spec.Resource
+ Hidden bool
*spec.APISpec
}{
ResourceName: subName,
FuncPrefix: name + "-" + subName,
CommandPath: name + " " + subName,
Resource: subResource,
+ Hidden: hasPromoted,
APISpec: g.Spec,
}
subParentPath := filepath.Join("internal", "cli", name+"_"+subName+".go")
@@ -567,8 +576,15 @@ func (g *Generator) Generate() error {
}
}
+ // Generate api discovery command when promoted commands exist (lets users browse hidden interfaces)
+ if hasPromoted {
+ if err := g.renderTemplate("api_discovery.go.tmpl", filepath.Join("internal", "cli", "api_discovery.go"), g.Spec); err != nil {
+ return fmt.Errorf("rendering api discovery: %w", err)
+ }
+ }
+
// Generate promoted top-level commands (user-friendly aliases for nested API commands)
- promotedCommands := buildPromotedCommands(g.Spec)
+ // promotedCommands was computed earlier (before resource rendering) for Hidden flag
for _, pc := range promotedCommands {
promotedData := struct {
PromotedName string
@@ -591,18 +607,27 @@ func (g *Generator) Generate() error {
}
}
+ // Build set of resource names that have promoted commands — root.go.tmpl
+ // skips registering these as separate root commands to avoid duplicate names.
+ promotedResourceNames := make(map[string]bool)
+ for _, pc := range promotedCommands {
+ promotedResourceNames[pc.ResourceName] = true
+ }
+
rootData := struct {
*spec.APISpec
- VisionSet VisionTemplateSet
- WorkflowConstructors []string
- InsightConstructors []string
- PromotedCommands []PromotedCommand
+ VisionSet VisionTemplateSet
+ WorkflowConstructors []string
+ InsightConstructors []string
+ PromotedCommands []PromotedCommand
+ PromotedResourceNames map[string]bool
}{
- APISpec: g.Spec,
- VisionSet: g.VisionSet,
- WorkflowConstructors: renderedWorkflowConstructors,
- InsightConstructors: renderedInsightConstructors,
- PromotedCommands: promotedCommands,
+ APISpec: g.Spec,
+ VisionSet: g.VisionSet,
+ WorkflowConstructors: renderedWorkflowConstructors,
+ InsightConstructors: renderedInsightConstructors,
+ PromotedCommands: promotedCommands,
+ PromotedResourceNames: promotedResourceNames,
}
if err := g.renderTemplate("root.go.tmpl", filepath.Join("internal", "cli", "root.go"), rootData); err != nil {
return fmt.Errorf("rendering root: %w", err)
@@ -1139,12 +1164,6 @@ func buildPromotedCommands(s *spec.APISpec) []PromotedCommand {
var promoted []PromotedCommand
usedNames := make(map[string]bool)
- // Collect resource group names so promoted commands don't collide with them
- resourceGroupNames := make(map[string]bool)
- for name := range s.Resources {
- resourceGroupNames[toKebab(name)] = true
- }
-
for name, resource := range s.Resources {
// Find the primary GET endpoint: prefer GET without positional params, else first GET
var bestName string
@@ -1180,9 +1199,6 @@ func buildPromotedCommands(s *spec.APISpec) []PromotedCommand {
if builtinCommands[promotedName] {
continue
}
- if resourceGroupNames[promotedName] {
- continue
- }
if usedNames[promotedName] {
continue
}
diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go
index d30cf246..d5632865 100644
--- a/internal/generator/generator_test.go
+++ b/internal/generator/generator_test.go
@@ -22,9 +22,9 @@ func TestGenerateProjectsCompile(t *testing.T) {
specPath string
expectedFiles int
}{
- {name: "stytch", specPath: filepath.Join("..", "..", "testdata", "stytch.yaml"), expectedFiles: 31},
- {name: "clerk", specPath: filepath.Join("..", "..", "testdata", "clerk.yaml"), expectedFiles: 36},
- {name: "loops", specPath: filepath.Join("..", "..", "testdata", "loops.yaml"), expectedFiles: 34},
+ {name: "stytch", specPath: filepath.Join("..", "..", "testdata", "stytch.yaml"), expectedFiles: 34},
+ {name: "clerk", specPath: filepath.Join("..", "..", "testdata", "clerk.yaml"), expectedFiles: 40},
+ {name: "loops", specPath: filepath.Join("..", "..", "testdata", "loops.yaml"), expectedFiles: 36},
}
for _, tt := range tests {
@@ -611,7 +611,7 @@ func TestToKebab(t *testing.T) {
func TestBuildPromotedCommands(t *testing.T) {
t.Parallel()
- t.Run("resource with list endpoint is NOT promoted (collides with resource group)", func(t *testing.T) {
+ t.Run("resource with list endpoint IS promoted (shortcut for resource group)", func(t *testing.T) {
t.Parallel()
s := &spec.APISpec{
Name: "test",
@@ -626,10 +626,11 @@ func TestBuildPromotedCommands(t *testing.T) {
},
}
promoted := buildPromotedCommands(s)
- assert.Empty(t, promoted, "promoted command should not be emitted when it collides with resource group name")
+ require.Len(t, promoted, 1)
+ assert.Equal(t, "users", promoted[0].PromotedName)
})
- t.Run("ISteamUser resource is NOT promoted (collides with resource group)", func(t *testing.T) {
+ t.Run("ISteamUser resource IS promoted (shortcut for resource group)", func(t *testing.T) {
t.Parallel()
s := &spec.APISpec{
Name: "test",
@@ -644,7 +645,8 @@ func TestBuildPromotedCommands(t *testing.T) {
},
}
promoted := buildPromotedCommands(s)
- assert.Empty(t, promoted, "promoted command should not be emitted when it collides with resource group name")
+ require.Len(t, promoted, 1)
+ assert.Equal(t, "steam-user", promoted[0].PromotedName)
})
t.Run("resource named version is skipped (collides with built-in)", func(t *testing.T) {
@@ -684,7 +686,7 @@ func TestBuildPromotedCommands(t *testing.T) {
assert.Empty(t, promoted)
})
- t.Run("prefers GET without positional params (collides with resource group)", func(t *testing.T) {
+ t.Run("prefers GET without positional params for promoted command", func(t *testing.T) {
t.Parallel()
s := &spec.APISpec{
Name: "test",
@@ -701,7 +703,9 @@ func TestBuildPromotedCommands(t *testing.T) {
},
}
promoted := buildPromotedCommands(s)
- assert.Empty(t, promoted, "promoted command collides with resource group name")
+ require.Len(t, promoted, 1)
+ assert.Equal(t, "items", promoted[0].PromotedName)
+ assert.Equal(t, "list", promoted[0].EndpointName, "should prefer the list endpoint (no positional params)")
})
t.Run("all built-in names are skipped", func(t *testing.T) {
@@ -748,12 +752,12 @@ func TestGeneratedOutput_PromotedCommandExists(t *testing.T) {
gen := New(apiSpec, outputDir)
require.NoError(t, gen.Generate())
- // Promoted command file should NOT exist because "users" collides with the
- // resource group command of the same name
+ // Promoted command file SHOULD exist — it provides a user-friendly shortcut.
+ // The resource group command is hidden from --help when promoted commands exist.
promotedFile := filepath.Join(outputDir, "internal", "cli", "promoted_users.go")
- assert.NoFileExists(t, promotedFile)
+ assert.FileExists(t, promotedFile)
- // The resource group command should still exist
+ // The resource group command should still exist (but hidden)
assert.FileExists(t, filepath.Join(outputDir, "internal", "cli", "users.go"))
}
@@ -788,9 +792,12 @@ func TestGeneratedOutput_PromotedCommandCompiles(t *testing.T) {
gen := New(apiSpec, outputDir)
require.NoError(t, gen.Generate())
- // Promoted files should NOT exist because they collide with resource group names
- assert.NoFileExists(t, filepath.Join(outputDir, "internal", "cli", "promoted_i-steam-user.go"))
- assert.NoFileExists(t, filepath.Join(outputDir, "internal", "cli", "promoted_items.go"))
+ // Promoted files SHOULD exist — they provide user-friendly shortcuts for resource groups.
+ // When promoted commands exist, resource parents are hidden from --help.
+ assert.FileExists(t, filepath.Join(outputDir, "internal", "cli", "promoted_steam-user.go"))
+ assert.FileExists(t, filepath.Join(outputDir, "internal", "cli", "promoted_items.go"))
+ // API discovery command should also be generated
+ assert.FileExists(t, filepath.Join(outputDir, "internal", "cli", "api_discovery.go"))
// Must compile
runGoCommand(t, outputDir, "mod", "tidy")
@@ -828,8 +835,8 @@ func TestGeneratedOutput_PromotedCommandNotForBuiltins(t *testing.T) {
// "version" should NOT have a promoted command (collides with built-in)
assert.NoFileExists(t, filepath.Join(outputDir, "internal", "cli", "promoted_version.go"))
- // "users" should NOT have a promoted command (collides with resource group)
- assert.NoFileExists(t, filepath.Join(outputDir, "internal", "cli", "promoted_users.go"))
+ // "users" SHOULD have a promoted command (shortcut for the resource group)
+ assert.FileExists(t, filepath.Join(outputDir, "internal", "cli", "promoted_users.go"))
}
// --- Unit 3: Auth Error Handling Tests ---
diff --git a/internal/generator/templates/api_discovery.go.tmpl b/internal/generator/templates/api_discovery.go.tmpl
new file mode 100644
index 00000000..987855ab
--- /dev/null
+++ b/internal/generator/templates/api_discovery.go.tmpl
@@ -0,0 +1,76 @@
+// Copyright {{currentYear}} {{.Owner}}. Licensed under Apache-2.0. See LICENSE.
+// Generated by CLI Printing Press (https://github.com/mvanhorn/cli-printing-press). DO NOT EDIT.
+
+package cli
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+func newAPICmd(flags *rootFlags) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "api [interface]",
+ Short: "Browse all API endpoints by interface name",
+ Long: `Browse and call any API endpoint using the raw interface names.
+
+The friendly top-level commands cover the most common operations.
+This command provides access to ALL endpoints for power users and
+agents that need full API coverage.
+
+Run 'api' with no arguments to list all interfaces.
+Run 'api <interface>' to see that interface's methods.`,
+ Example: ` # List all available interfaces
+ {{.Name}}-pp-cli api
+
+ # Show methods for a specific interface
+ {{.Name}}-pp-cli api <interface-name>`,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ root := cmd.Root()
+
+ if len(args) > 0 {
+ target := strings.ToLower(args[0])
+ for _, child := range root.Commands() {
+ if child.Hidden && strings.ToLower(child.Name()) == target {
+ methods := child.Commands()
+ if len(methods) == 0 {
+ return child.Help()
+ }
+ fmt.Fprintf(cmd.OutOrStdout(), "%s — %s\n\nMethods:\n", child.Name(), child.Short)
+ for _, method := range methods {
+ fmt.Fprintf(cmd.OutOrStdout(), " %-50s %s\n", child.Name()+" "+method.Name(), method.Short)
+ }
+ fmt.Fprintf(cmd.OutOrStdout(), "\nUse '%s-pp-cli %s <method> --help' for details.\n", "{{.Name}}", child.Name())
+ return nil
+ }
+ }
+ return fmt.Errorf("interface %q not found. Run '%s-pp-cli api' to list all interfaces", args[0], "{{.Name}}")
+ }
+
+ var interfaces []string
+ for _, child := range root.Commands() {
+ if child.Hidden {
+ interfaces = append(interfaces, fmt.Sprintf(" %-45s %s", child.Name(), child.Short))
+ }
+ }
+ sort.Strings(interfaces)
+
+ if len(interfaces) == 0 {
+ fmt.Fprintln(cmd.OutOrStdout(), "No hidden API interfaces found.")
+ return nil
+ }
+
+ fmt.Fprintf(cmd.OutOrStdout(), "Available API interfaces (%d):\n\n", len(interfaces))
+ for _, line := range interfaces {
+ fmt.Fprintln(cmd.OutOrStdout(), line)
+ }
+ fmt.Fprintf(cmd.OutOrStdout(), "\nUse '%s-pp-cli api <interface>' to see methods.\n", "{{.Name}}")
+ return nil
+ },
+ }
+
+ return cmd
+}
diff --git a/internal/generator/templates/command_parent.go.tmpl b/internal/generator/templates/command_parent.go.tmpl
index 24de3a3d..6f613c35 100644
--- a/internal/generator/templates/command_parent.go.tmpl
+++ b/internal/generator/templates/command_parent.go.tmpl
@@ -11,6 +11,9 @@ func new{{camel .FuncPrefix}}Cmd(flags *rootFlags) *cobra.Command {
cmd := &cobra.Command{
Use: "{{.ResourceName}}",
Short: "{{oneline .Resource.Description}}",
+{{- if .Hidden}}
+ Hidden: true,
+{{- end}}
}
{{range $eName, $endpoint := .Resource.Endpoints}}
cmd.AddCommand(new{{camel $.FuncPrefix}}{{camel $eName}}Cmd(flags))
diff --git a/internal/generator/templates/root.go.tmpl b/internal/generator/templates/root.go.tmpl
index 0fdc7a85..1cbdb02b 100644
--- a/internal/generator/templates/root.go.tmpl
+++ b/internal/generator/templates/root.go.tmpl
@@ -98,7 +98,9 @@ func Execute() error {
}
{{- range $name, $resource := .Resources}}
- rootCmd.AddCommand(new{{camel $name}}Cmd(&flags)) {{/* FuncPrefix matches resource name for top-level */}}
+{{- if not (index $.PromotedResourceNames $name)}}
+ rootCmd.AddCommand(new{{camel $name}}Cmd(&flags))
+{{- end}}
{{- end}}
rootCmd.AddCommand(newDoctorCmd(&flags))
rootCmd.AddCommand(newAuthCmd(&flags))
@@ -129,6 +131,9 @@ func Execute() error {
{{- range .InsightConstructors}}
rootCmd.AddCommand(new{{.}}Cmd(&flags))
{{- end}}
+{{- if .PromotedCommands}}
+ rootCmd.AddCommand(newAPICmd(&flags))
+{{- end}}
{{- range .PromotedCommands}}
rootCmd.AddCommand(new{{camel .PromotedName}}PromotedCmd(&flags))
{{- end}}
← 360db307 fix(skills): publish skill checks for merged PRs before reus
·
back to Cli Printing Press
·
fix(cli): SQL reserved word safety, promoted subcommands, ve 289ac4bf →