Skip to content

[Feat] Add command catalog discovery#3

Merged
samzong merged 1 commit intomainfrom
feat/command-catalog
Apr 27, 2026
Merged

[Feat] Add command catalog discovery#3
samzong merged 1 commit intomainfrom
feat/command-catalog

Conversation

@samzong
Copy link
Copy Markdown
Owner

@samzong samzong commented Apr 27, 2026

What's changed?

  • Add a versioned command catalog exposed through commands, commands show, and commands schema.
  • Add catalog-backed search for generated commands.
  • Attach catalog payloads to Cobra commands via annotations and cover path, hidden, alias, auth, formatter, and JSON behavior with tests.

Why

  • Gives humans and agents a structured source of truth for generated CLI commands without scraping help output.

Signed-off-by: samzong <samzong.lu@gmail.com>
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a command catalog system for the lathe CLI, adding subcommands to list, show, search, and view the schema of generated commands. The implementation includes a new catalog generation and searching mechanism in the runtime package that leverages cobra command annotations for metadata storage. Review feedback focuses on improving code idiomaticity and performance by replacing the sort package with the slices package for sorting catalog commands, search results, and formatter names.

Comment thread pkg/runtime/catalog.go
import (
"encoding/json"
"slices"
"sort"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The sort package is no longer needed if we switch to the more idiomatic and performant slices.SortFunc for sorting the catalog commands and search results.

Suggested change
"sort"
"slices"

Comment thread pkg/runtime/catalog.go
Comment on lines +134 to +136
sort.Slice(commands, func(i, j int) bool {
return slices.Compare(commands[i].Path, commands[j].Path) < 0
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since Go 1.21, slices.SortFunc is preferred over sort.Slice as it is type-safe and avoids reflection. Additionally, slices.Compare already returns the int value expected by SortFunc, making the implementation cleaner.

Suggested change
sort.Slice(commands, func(i, j int) bool {
return slices.Compare(commands[i].Path, commands[j].Path) < 0
})
slices.SortFunc(commands, func(a, b CatalogCommand) int {
return slices.Compare(a.Path, b.Path)
})

Comment thread pkg/runtime/catalog.go
Comment on lines +181 to +186
sort.Slice(results, func(i, j int) bool {
if results[i].Score != results[j].Score {
return results[i].Score > results[j].Score
}
return slices.Compare(results[i].Command.Path, results[j].Command.Path) < 0
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using slices.SortFunc here improves readability and performance by avoiding reflection. The logic for descending score and ascending path remains clear.

Suggested change
sort.Slice(results, func(i, j int) bool {
if results[i].Score != results[j].Score {
return results[i].Score > results[j].Score
}
return slices.Compare(results[i].Command.Path, results[j].Command.Path) < 0
})
slices.SortFunc(results, func(a, b SearchResult) int {
if a.Score != b.Score {
return b.Score - a.Score
}
return slices.Compare(a.Command.Path, b.Command.Path)
})

Comment thread pkg/runtime/formatter.go
import "io"
import (
"io"
"sort"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Prefer using the slices package for sorting simple slices of ordered types like strings.

Suggested change
"sort"
"slices"

Comment thread pkg/runtime/formatter.go
}
extra = append(extra, name)
}
sort.Strings(extra)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Use slices.Sort for a more modern and efficient way to sort a slice of strings.

Suggested change
sort.Strings(extra)
slices.Sort(extra)

@samzong samzong merged commit af4c2a2 into main Apr 27, 2026
1 check passed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 737127ab06

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pkg/lathe/lathe.go
Comment on lines +41 to +42
cmd.AddCommand(commandsCmd(m))
cmd.AddCommand(searchCmd(m))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Guard top-level command names from module collisions

Adding fixed root commands commands and search without any collision check can break downstream CLIs that already have modules with those names: generated modules are mounted onto root after NewApp, so a module named search/commands will conflict at the same command path and become ambiguous or unreachable. This is a regression for previously valid module names and should be prevented (for example by reserving/validating names at generation time or namespacing these introspection commands).

Useful? React with 👍 / 👎.

Comment thread pkg/lathe/catalog.go
Comment on lines +34 to +35
addJSONFlag(cmd, &jsonOut, "Emit catalog JSON")
cmd.Flags().BoolVar(&includeHidden, "include-hidden", false, "Include hidden commands")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid shadowing subcommand flags on commands

The parent commands command defines local --json/--include-hidden flags, and commands show defines flags with the same names again; when users place flags before the subcommand (for example, commands --json show ... or commands --include-hidden show ...), Cobra consumes the parent flag value but show reads its own separate variables, so the request is silently ignored. This makes valid-looking invocations return non-JSON output or fail to find hidden commands unexpectedly.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant