Ver Fonte

move the definition commands under the keyboard command

`definition` had two children and `keyboard` had one, and the one was `info`
because a bare `info` was already the per-zone RGB state. So `keyboard` existed
to disambiguate that collision rather than to hold anything, which is why the
root help showed an empty namespace beside a `definition` that appeared to have
no relation to it.

What sits under it now is coherent on both sides. `fetch` writes a file that
belongs to a board and looks it up by the board's vendor and product ID, so
there is nothing to fetch without one. `definitions` lists what is in use, one
entry per board, and never opens a board — the same profile as `keyboard info`,
which was already in the group.

The listing is named `definitions` and not `list` on purpose. Under `keyboard`,
`list` reads as listing the keyboards, which is what `info` does, and the root
already has a `list` that means the profile store; one verb must not name two
stores. `definitions` collides with nothing and says what it lists.

The five messages that told a user to run `definition fetch` name `keyboard
fetch` now, and README quotes four of them verbatim, so the two move together.
There is no alias for the old name: a silent one would keep it alive, which is
the drift this removes, in the other direction.
Paul-Dieter Klumpp há 1 semana atrás
pai
commit
dbc872c7ca

+ 3 - 3
.claude/skills/qmk-rgb/SKILL.md

@@ -27,7 +27,7 @@ qmk-rgb-tool effect --list                    # Effects per zone, one per line
 qmk-rgb-tool --json effect --list             # The same, as JSON for parsing
 qmk-rgb-tool keyboard info                    # Connected keyboards
 qmk-rgb-tool info                             # Current RGB state
-qmk-rgb-tool definition list                  # Which definition files are in use, and where each is from
+qmk-rgb-tool keyboard definitions            # Which definition files are in use, and where each is from
 ```
 
 Present the raw output to the user. Never duplicate documentation — the tool output is authoritative.
@@ -74,8 +74,8 @@ keyboard has no names, say so and offer the two ways to supply them, in this
 order:
 
 ```bash
-qmk-rgb-tool definition fetch   # download the definition for the connected board
-qmk-rgb-tool definition list    # every definition in use, from the per-user directory and built in
+qmk-rgb-tool keyboard fetch                  # download the definition for the connected board
+qmk-rgb-tool keyboard definitions            # every definition in use, from the per-user directory and built in
 ```
 
 `fetch` needs the board to be in VIA's collection. Many are not, including the

+ 5 - 5
AGENTS.md

@@ -48,7 +48,7 @@ Each of the two is one directory, and it is both what is written and what is
 read: `definitionsPath()` and `profilesPath()`, and nothing else. Both were
 searches until they were not — next to the executable, then the working
 directory, then the user's — and the search was a defect in both cases, for the
-same reason in reverse. A definition is written by `definition fetch` and read by
+same reason in reverse. A definition is written by `keyboard fetch` and read by
 every command, so a directory beside the binary hides the file the user just
 fetched, for as long as the binary is run from a checkout, which is where it is
 run from. A profile is written to the user's directory and read from a
@@ -241,7 +241,7 @@ measured on VIA's own collection of 2029 definitions rather than assumed:
   what a document should tell a user to type.
 - A fetched file has to be parsed and matched before it is believed. VIA answers
   an unknown board with its own web page and HTTP 200, so status alone proves
-  nothing. `definition fetch` tries v3 then v2, and only stores a document that
+  nothing. `keyboard fetch` tries v3 then v2, and only stores a document that
   parses and names the board that was asked about.
 
 The files are VIA's format, but their addressing is QMK's, and that is not a
@@ -289,18 +289,18 @@ transcribed per board and cannot be generated from a common source.
 
 ## Output Shape
 
-`keyboard info`, `info`, `list`, `effect --list` and `definition list` print text,
+`keyboard info`, `info`, `list`, `effect --list` and `keyboard definitions` print text,
 because that is what a person reads, and JSON only behind the persistent `--json`.
 The field names are the ones the JSON always had, so a consumer that passes the
 flag is unaffected — where a field had to be added, it is added rather than
-renamed or reshaped. `definition list` grew a `source` field per entry for exactly
+renamed or reshaped. `keyboard definitions` grew a `source` field per entry for exactly
 this reason: it now lists the definitions built into the binary as well as the
 ones in the user directory, and a path alone does not say which of the two a line
 is, because a built-in one has a path relative to the build. A command that emits
 structured data and neither honours `--json` nor says why is the bug this rule
 exists for. Two shapes are deliberately
 not in that list: `effect` with no argument routes to `effect --list`, and
-`definition fetch` writes a file and prints a line about it.
+`keyboard fetch` writes a file and prints a line about it.
 
 `keyboard info` does not open the board, so it must not report the board's
 channels or an effect list from one: it reports the name and whether this tool has

+ 13 - 13
README.md

@@ -40,8 +40,8 @@ when you open a board in its web app — so the tool needs that board's file, th
 VIA does. Identify the keyboard, then get its definition:
 
 ```bash
-qmk-rgb-tool definition fetch   # download the definition for the connected keyboard
-qmk-rgb-tool definition list    # every definition in use, and where each is from
+qmk-rgb-tool keyboard fetch         # download the definition for the connected keyboard
+qmk-rgb-tool keyboard definitions   # every definition in use, and where each is from
 ```
 
 **Where those files live.** Both directories are under the platform's per-user
@@ -54,7 +54,7 @@ configuration directory, and each is read from there and written to there:
 | Windows | `%AppData%\qmk-rgb-tool\` |
 
 One directory per kind, and not a search. A definition is written by
-`definition fetch` and read by every command, so a search path would mean the
+`keyboard fetch` and read by every command, so a search path would mean the
 file a fetch produced is not the file the next command reads. A profile is
 written there and read there, so `save <name>` followed by `load <name>` finds
 what was just written and a same-named file in a checkout cannot be loaded in its
@@ -324,20 +324,20 @@ commands need the catalog and say so rather than guessing:
 
 ```
 $ qmk-rgb-tool effect wave
-Error: no effect names for this keyboard: run `definition fetch` for its VIA definition, or set an
+Error: no effect names for this keyboard: run `keyboard fetch` for its VIA definition, or set an
 effect by number with `effect <index>`
 
 $ qmk-rgb-tool enable
-Error: this keyboard has no effect names, so `enable` cannot choose an effect: run `definition fetch` for
+Error: this keyboard has no effect names, so `enable` cannot choose an effect: run `keyboard fetch` for
 its VIA definition, or set one with `effect <index>`
 
 $ qmk-rgb-tool load paul
-Warning: profile "paul" has no effect names for this keyboard, so nothing applied; run `definition fetch` for
+Warning: profile "paul" has no effect names for this keyboard, so nothing applied; run `keyboard fetch` for
 its VIA definition
 
 $ qmk-rgb-tool save paul
 Warning: this keyboard has no effect names, so the profile records effect "unknown" and cannot restore it; run
-`definition fetch` for its VIA definition, or set an effect with `effect <index>`
+`keyboard fetch` for its VIA definition, or set an effect with `effect <index>`
 ```
 
 `enable` needs it because it has to choose an effect to turn a channel on.
@@ -466,7 +466,7 @@ failure, but the summary line always states the value that was actually applied.
 - **Effect names from VIA definition files** — the vendor's own names, read at runtime; no name is hand-written, so there is one source per board, and a file the user places overrides the one built in
 - **Compatibility aliases** — `off`, `breathe`, `rainbow`, `rainbow_wave`, `solid`, `static` resolve to correct effect IDs per channel
 - **Reactive & splash effects** — honor `color` and `speed` for key-press illumination
-- **Machine-parseable output** — text by default, JSON behind `--json` for `keyboard info`, `info`, `list`, `effect --list` and `definition list`
+- **Machine-parseable output** — text by default, JSON behind `--json` for `keyboard info`, `info`, `list`, `effect --list` and `keyboard definitions`
 - **Agent-friendly** — designed for automation, scripting, and CLI-first workflows
 - **Multiple devices** — `keyboard info` numbers each keyboard; `--device <n>` targets one
 
@@ -673,7 +673,7 @@ a channel the same thing, and a name is matched ignoring case. On a board whose
 definition writes `Backlight`, all of `--zone backlight`, `--zone Backlight` and
 `--zone rgb_matrix` reach the same channel: the label is the name, the subsystem
 stays accepted because it follows from the channel number. `qmk-rgb-tool
-definition list` prints the label beside the subsystem it stands for, and says
+keyboard definitions` prints the label beside the subsystem it stands for, and says
 where each definition came from — `user` for a file in the per-user directory,
 `built-in` for one compiled into the binary:
 
@@ -732,8 +732,8 @@ board", and that file is gone, so the field would have been unanswerable:
 | `qmk-rgb-tool effect <name\|index>`   | Set an effect by name, or a raw effect index 0–255, verified by read-back; a board that does not implement the index clamps it to the highest it does |
 | `qmk-rgb-tool effect`                 | With no argument, list every effect per channel |
 | `qmk-rgb-tool effect --list`          | The same list, as a flag                   |
-| `qmk-rgb-tool definition fetch`       | Download the VIA definition for the connected keyboard |
-| `qmk-rgb-tool definition list`        | List every definition in use, from the per-user directory and built into the binary, each marked with which it is |
+| `qmk-rgb-tool keyboard fetch`         | Download the VIA definition for the connected keyboard |
+| `qmk-rgb-tool keyboard definitions`   | List every definition in use, from the per-user directory and built into the binary, each marked with which it is |
 | `qmk-rgb-tool brightness <val>`       | Set brightness (0–255) on selected zones, verified by read-back |
 | `qmk-rgb-tool speed <val>`            | Set effect speed (0–255) on selected zones, verified by read-back; on `logo` and `side` only 0, 1 and 4 are reachable |
 | `qmk-rgb-tool color <hex>`            | Set color (e.g. `ff0000`) on selected zones |
@@ -742,7 +742,7 @@ board", and that file is gone, so the field would have been unanswerable:
 | `qmk-rgb-tool --zone <channel> ...`   | Target one channel: `backlight`, `rgblight`, `rgb_matrix`, `audio` or `led_matrix`, or the name the board's definition gives it |
 | `qmk-rgb-tool --device <n> ...`      | Target keyboard by number (see `keyboard info`) |
 | `qmk-rgb-tool --definition <path>`  | Read effect names from this VIA definition file instead of the one in the data directory; applies to every command that resolves names, and a file for another board is refused |
-| `qmk-rgb-tool --json`               | Print JSON instead of text, for `keyboard info`, `info`, `list`, `effect --list` and `definition list` |
+| `qmk-rgb-tool --json`               | Print JSON instead of text, for `keyboard info`, `info`, `list`, `effect --list` and `keyboard definitions` |
 | `qmk-rgb-tool -v`, `--version`       | Print the version                          |
 | `qmk-rgb-tool save [name]`            | Save current RGB state as `<name>.json` in the per-user `profiles/` (name lowercased, non-`[a-z0-9-_]` mapped to `-`, a leading `-` prefixed with `unnamed-`); without a name it writes `default` |
 | `qmk-rgb-tool load [name]`            | Load and apply a profile by name from the per-user `profiles/`; without a name it loads `default` |
@@ -755,7 +755,7 @@ token. `effect`, `load`, `save` and `delete` accept an optional name.
 `brightness`, `speed` and `color` require exactly one argument. `effect` takes one
 argument too, and accepts either a name or a raw effect ID.
 
-`keyboard info`, `info`, `list`, `definition list` and `effect --list` print
+`keyboard info`, `info`, `list`, `keyboard definitions` and `effect --list` print
 text, because a person reads them. Pass `--json` for the machine shape, which is
 the same data with the same field names as before:
 

+ 1 - 1
cmd/qmk-rgb-tool/channels_test.go

@@ -447,7 +447,7 @@ func TestRootHelpGroupsTheCommands(t *testing.T) {
 		"Lighting Commands:",
 		"Profile Commands:",
 		"Keyboard Commands:",
-		"save", "load", "list", "delete", "effect", "definition", "keyboard",
+		"save", "load", "list", "delete", "effect", "keyboard",
 	} {
 		if !strings.Contains(help, want) {
 			t.Errorf("--help does not mention %q", want)

+ 2 - 2
cmd/qmk-rgb-tool/datadir.go

@@ -15,7 +15,7 @@ import (
 // There is one such directory and both kinds of file are read from it and
 // written to it. There used to be a search: definitions and profiles were looked
 // for next to the executable and in the working directory before the user's, and
-// that was wrong for both. A definition is written by `definition fetch` and read
+// that was wrong for both. A definition is written by `keyboard fetch` and read
 // by every command, so a search path can hide the file the user just fetched. A
 // profile is written to the user's directory, so a search path for reading can
 // find a same-named file in a checkout instead and load that one — the same name,
@@ -46,7 +46,7 @@ func userDataDir() string {
 }
 
 // definitionsPath is where the definition files live: the per-user directory,
-// and nowhere else. A `definition fetch` writes here, so anything else would mean
+// and nowhere else. A `keyboard fetch` writes here, so anything else would mean
 // the file a fetch produced is not the file the next command reads. The
 // definitions built into the binary are consulted after this one, by
 // candidateDefinitions in catalog.go.

+ 1 - 1
cmd/qmk-rgb-tool/datadir_test.go

@@ -36,7 +36,7 @@ func TestDataDirectoriesAreTheUserDirectory(t *testing.T) {
 // directory, then the user's. Both reasons for that are gone, and a test has to
 // say so, because the search is the kind of thing that comes back.
 //
-// A search path for a definition hides the file `definition fetch` just wrote,
+// A search path for a definition hides the file `keyboard fetch` just wrote,
 // because a definitions directory beside the binary exists for as long as the
 // binary is run from a checkout, and it wins. A search path for a profile finds a
 // same-named file in a checkout and loads that one instead of the one the user

+ 15 - 21
cmd/qmk-rgb-tool/definition.go

@@ -31,20 +31,10 @@ var httpGet = func(url string) ([]byte, int, error) {
 	return body, resp.StatusCode, err
 }
 
-func NewDefinitionCmd() *cobra.Command {
-	cmd := &cobra.Command{
-		Use:   "definition",
-		Short: "Manage keyboard definition files",
-		Long: "A keyboard's effect names come from a VIA definition file, the same one VIA\n" +
-			"itself uses. `fetch` downloads the file for the connected keyboard into the\n" +
-			"data directory; to use a file you already have, put it in that directory or\n" +
-			"pass it with --definition.",
-	}
-	cmd.AddCommand(newDefinitionFetchCmd(), newDefinitionListCmd())
-	return cmd
-}
-
-func newDefinitionFetchCmd() *cobra.Command {
+// NewKeyboardFetchCmd is `keyboard fetch`. It belongs to the keyboard command
+// because what it fetches belongs to a board: the file is looked up by the
+// board's vendor and product ID, so there is nothing to fetch without one.
+func NewKeyboardFetchCmd() *cobra.Command {
 	return &cobra.Command{
 		Use:   "fetch",
 		Short: "Download the definition file for the connected keyboard",
@@ -53,20 +43,24 @@ func newDefinitionFetchCmd() *cobra.Command {
 			"an unknown one with its own web page, so a downloaded file is parsed and\n" +
 			"matched against the keyboard before it is stored.",
 		Args: cobra.NoArgs,
-		RunE: runDefinitionFetch,
+		RunE: runKeyboardFetch,
 	}
 }
 
-func newDefinitionListCmd() *cobra.Command {
+// NewKeyboardDefinitionsCmd is `keyboard definitions`, and the name is the noun
+// rather than a verb on purpose. `keyboard list` reads as listing the
+// keyboards, which is what `keyboard info` does, and the root already has a
+// `list` that means the profile store; one verb must not mean two stores.
+func NewKeyboardDefinitionsCmd() *cobra.Command {
 	return &cobra.Command{
-		Use:   "list",
-		Short: "List the definition files in the data directory",
+		Use:   "definitions",
+		Short: "List the definition files in the data directory, and those built in",
 		Args:  cobra.NoArgs,
-		RunE:  runDefinitionList,
+		RunE:  runKeyboardDefinitions,
 	}
 }
 
-func runDefinitionFetch(cmd *cobra.Command, args []string) error {
+func runKeyboardFetch(cmd *cobra.Command, args []string) error {
 	target, err := prepareTarget()
 	if err != nil {
 		return err
@@ -94,7 +88,7 @@ func runDefinitionFetch(cmd *cobra.Command, args []string) error {
 	return nil
 }
 
-func runDefinitionList(cmd *cobra.Command, args []string) error {
+func runKeyboardDefinitions(cmd *cobra.Command, args []string) error {
 	dir := definitionsPath()
 	// Both sources are listed, not just the directory: the file built into the
 	// binary is where the names for a board that cannot be fetched come from, and

+ 13 - 19
cmd/qmk-rgb-tool/definition_test.go

@@ -29,14 +29,13 @@ func TestFetchDefinitionStoresTheFileForTheBoard(t *testing.T) {
 		return nil, http.StatusNotFound, errors.New("404")
 	})
 
-	cmd := NewDefinitionCmd()
+	cmd := NewKeyboardFetchCmd()
 	var out, errOut strings.Builder
 	cmd.SetOut(&out)
 	cmd.SetErr(&errOut)
-	cmd.SetArgs([]string{"fetch"})
 
 	if err := cmd.Execute(); err != nil {
-		t.Fatalf("definition fetch error = %v (stderr %q)", err, errOut.String())
+		t.Fatalf("keyboard fetch error = %v (stderr %q)", err, errOut.String())
 	}
 
 	if len(requested) != 1 || !strings.Contains(requested[0], "/v3/305419896.json") {
@@ -67,15 +66,14 @@ func TestFetchDefinitionRejectsAPageThatIsNotADefinition(t *testing.T) {
 		return []byte("<!doctype html><html><head><title>VIA</title></head></html>"), http.StatusOK, nil
 	})
 
-	cmd := NewDefinitionCmd()
+	cmd := NewKeyboardFetchCmd()
 	var out, errOut strings.Builder
 	cmd.SetOut(&out)
 	cmd.SetErr(&errOut)
-	cmd.SetArgs([]string{"fetch"})
 
 	err := cmd.Execute()
 	if err == nil {
-		t.Fatal("definition fetch = nil error, want a failure for a non-definition")
+		t.Fatal("keyboard fetch = nil error, want a failure for a non-definition")
 	}
 	if !strings.Contains(err.Error(), "no definition") {
 		t.Errorf("error = %q, want it to say there is no definition", err)
@@ -247,7 +245,7 @@ func stubTargetData(vendorID, productID uint16) targetDeviceData {
 	}
 }
 
-// definition list is structured data, so --json has to reach it like every other
+// keyboard definitions is structured data, so --json has to reach it like every other
 // listing command; text by default is no excuse for a missing machine shape. The
 // definitions built into the binary are listed beside the ones in the user
 // directory, and each carries which of the two it is.
@@ -259,13 +257,12 @@ func TestDefinitionListHonoursTheJSONFlag(t *testing.T) {
 	t.Cleanup(forceDefinitionsDir(t, dir))
 
 	var out, errOut strings.Builder
-	cmd := NewDefinitionCmd()
+	cmd := NewKeyboardDefinitionsCmd()
 	cmd.SetOut(&out)
 	cmd.SetErr(&errOut)
-	cmd.SetArgs([]string{"list"})
 	withJSON(t)
 	if err := cmd.Execute(); err != nil {
-		t.Fatalf("definition list --json error = %v", err)
+		t.Fatalf("keyboard definitions --json error = %v", err)
 	}
 
 	var payload struct {
@@ -311,13 +308,12 @@ func TestDefinitionListShowsTheBuiltInDefinitions(t *testing.T) {
 	t.Cleanup(forceDefinitionsDir(t, t.TempDir()))
 
 	var out, errOut strings.Builder
-	cmd := NewDefinitionCmd()
+	cmd := NewKeyboardDefinitionsCmd()
 	cmd.SetOut(&out)
 	cmd.SetErr(&errOut)
-	cmd.SetArgs([]string{"list"})
 	withJSON(t)
 	if err := cmd.Execute(); err != nil {
-		t.Fatalf("definition list --json error = %v", err)
+		t.Fatalf("keyboard definitions --json error = %v", err)
 	}
 
 	var payload struct {
@@ -351,12 +347,11 @@ func TestDefinitionListReportsThatAUserFileShadowsABuiltInOne(t *testing.T) {
 	t.Cleanup(forceDefinitionsDir(t, dir))
 
 	var out, errOut strings.Builder
-	cmd := NewDefinitionCmd()
+	cmd := NewKeyboardDefinitionsCmd()
 	cmd.SetOut(&out)
 	cmd.SetErr(&errOut)
-	cmd.SetArgs([]string{"list"})
 	if err := cmd.Execute(); err != nil {
-		t.Fatalf("definition list error = %v", err)
+		t.Fatalf("keyboard definitions error = %v", err)
 	}
 	if !strings.Contains(out.String(), "shadows the built-in copy") {
 		t.Errorf("stdout = %q, want it to say the user file overrides the built-in one", out.String())
@@ -371,12 +366,11 @@ func TestDefinitionListPrintsTextByDefault(t *testing.T) {
 	t.Cleanup(forceDefinitionsDir(t, dir))
 
 	var out, errOut strings.Builder
-	cmd := NewDefinitionCmd()
+	cmd := NewKeyboardDefinitionsCmd()
 	cmd.SetOut(&out)
 	cmd.SetErr(&errOut)
-	cmd.SetArgs([]string{"list"})
 	if err := cmd.Execute(); err != nil {
-		t.Fatalf("definition list error = %v", err)
+		t.Fatalf("keyboard definitions error = %v", err)
 	}
 	var probe any
 	if err := json.Unmarshal([]byte(out.String()), &probe); err == nil {

+ 1 - 1
cmd/qmk-rgb-tool/enable.go

@@ -25,7 +25,7 @@ func NewEnableCmd() *cobra.Command {
 			for _, ch := range channels {
 				if _, ok := catalog.DefaultEffect(ch); !ok {
 					return fmt.Errorf("this keyboard has no effect names, so `enable` cannot choose an effect: " +
-						"run `definition fetch` for its VIA definition, or set one with `effect <index>`")
+						"run `keyboard fetch` for its VIA definition, or set one with `effect <index>`")
 				}
 			}
 

+ 13 - 2
cmd/qmk-rgb-tool/main.go

@@ -61,10 +61,18 @@ func main() {
 	Execute()
 }
 
+// keyboardCmd is the namespace for everything that is about one board rather
+// than about its lighting: which boards are connected, and the definition file
+// whose effect names belong to a board. The definition prose lives here because
+// there is no `definition` command of its own any more.
 var keyboardCmd = &cobra.Command{
 	Use:     "keyboard",
 	Short:   "Keyboard management commands",
 	GroupID: groupKeyboard,
+	Long: "A keyboard's effect names come from a VIA definition file, the same one VIA\n" +
+		"itself uses. `fetch` downloads the file for the connected keyboard into the\n" +
+		"data directory; to use a file you already have, put it in that directory or\n" +
+		"pass it with --definition.",
 }
 
 // inGroup places a command in one of the root help's groups.
@@ -126,7 +134,11 @@ func init() {
 // same tree the binary runs and check the grouping is real, rather than repeating
 // a list that could fall behind the one that ships.
 func registerCommands(root *cobra.Command) {
-	keyboardCmd.AddCommand(keyboardInfoCmd)
+	keyboardCmd.AddCommand(
+		keyboardInfoCmd,
+		NewKeyboardFetchCmd(),
+		NewKeyboardDefinitionsCmd(),
+	)
 
 	root.AddCommand(
 		inGroup(NewEnableCmd(), groupLighting),
@@ -140,7 +152,6 @@ func registerCommands(root *cobra.Command) {
 		inGroup(NewProfileLoadCmd(), groupProfile),
 		inGroup(NewProfileListCmd(), groupProfile),
 		inGroup(NewProfileDeleteCmd(), groupProfile),
-		inGroup(NewDefinitionCmd(), groupKeyboard),
 		inGroup(keyboardCmd, groupKeyboard),
 	)
 }

+ 2 - 2
cmd/qmk-rgb-tool/profile.go

@@ -224,7 +224,7 @@ func loadProfileFromDevice(name string, warn io.Writer) error {
 		// restored. Say so here, where the user can still act on it.
 		fmt.Fprintf(warn,
 			"Warning: this keyboard has no effect names, so the profile records effect %q and cannot restore it; "+
-				"run `definition fetch` for its VIA definition, or set an effect with `effect <index>`\n", "unknown")
+				"run `keyboard fetch` for its VIA definition, or set an effect with `effect <index>`\n", "unknown")
 	}
 
 	p := &Profile{
@@ -329,7 +329,7 @@ func NewProfileLoadCmd() *cobra.Command {
 			if catalog == nil {
 				fmt.Fprintf(cmd.ErrOrStderr(),
 					"Warning: profile %q has no effect names for this keyboard, so nothing applied; "+
-						"run `definition fetch` for its VIA definition\n", name)
+						"run `keyboard fetch` for its VIA definition\n", name)
 				return nil
 			}
 

+ 1 - 1
definitions/README.md

@@ -5,7 +5,7 @@ in this directory, so that `go install` delivers them: it copies a binary and
 creates no data directory, and a board VIA does not carry cannot be fetched.
 
 This is not the directory the tool reads at runtime. That is the per-user
-`definitions/` directory the top-level README names; `definition fetch` writes
+`definitions/` directory the top-level README names; `keyboard fetch` writes
 there, and a file placed there — or passed with `--definition` — takes precedence
 over the one built in. To use or correct a definition, put it there, not here.
 

+ 1 - 1
internal/rgb/catalog.go

@@ -205,7 +205,7 @@ func ResolveEffect(catalog *Catalog, name string, channels []via.Channel, explic
 		// Both ways out belong in the message: the board is still drivable by
 		// number, and the names are one command away. A user who reads only the
 		// error should not have to find either out elsewhere.
-		return nil, nil, fmt.Errorf("no effect names for this keyboard: run `definition fetch` for its VIA definition, " +
+		return nil, nil, fmt.Errorf("no effect names for this keyboard: run `keyboard fetch` for its VIA definition, " +
 			"or set an effect by number with `effect <index>`")
 	}
 

+ 1 - 1
internal/rgb/definition_test.go

@@ -373,7 +373,7 @@ func TestMissingCatalogErrorNamesBothWaysOut(t *testing.T) {
 	if err == nil {
 		t.Fatal("ResolveEffect(nil catalog) = nil error, want one")
 	}
-	for _, want := range []string{"`definition fetch`", "`effect <index>`"} {
+	for _, want := range []string{"`keyboard fetch`", "`effect <index>`"} {
 		if !strings.Contains(err.Error(), want) {
 			t.Errorf("error = %q, want it to mention %q", err, want)
 		}