From 7bf060986de5f3e790e425ccb21df8a362aed189 Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 10:10:56 +0000 Subject: [PATCH] fix(help): add recovery hints to help lookups Co-Authored-By: Virgil --- cmd/core/help/cmd.go | 12 ++++++++++++ cmd/core/help/cmd_test.go | 32 ++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/cmd/core/help/cmd.go b/cmd/core/help/cmd.go index f87472e..1afbc4f 100644 --- a/cmd/core/help/cmd.go +++ b/cmd/core/help/cmd.go @@ -2,6 +2,7 @@ package help import ( "bufio" + "fmt" "strings" "forge.lthn.ai/core/cli/pkg/cli" @@ -38,7 +39,10 @@ func AddHelpCommands(root *cli.Command) { return suggestErr } cli.Blank() + renderHelpHint(args[0]) + return cli.Err("help topic %q not found", args[0]) } + renderHelpHint(args[0]) return cli.Err("help topic %q not found", args[0]) } @@ -89,6 +93,7 @@ func searchHelpTopics(catalog *gohelp.Catalog, query string) error { func renderSearchResults(results []*gohelp.SearchResult, query string) error { if len(results) == 0 { + renderHelpHint(query) return cli.Err("no help topics matched %q", query) } @@ -102,6 +107,13 @@ func renderSearchResults(results []*gohelp.SearchResult, query string) error { return nil } +func renderHelpHint(query string) { + cli.Hint("browse", "core help") + if trimmed := strings.TrimSpace(query); trimmed != "" { + cli.Hint("search", fmt.Sprintf("core help search %q", trimmed)) + } +} + func renderTopicList(topics []*gohelp.Topic) error { if len(topics) == 0 { return cli.Err("no help topics available") diff --git a/cmd/core/help/cmd_test.go b/cmd/core/help/cmd_test.go index 655e80c..3b8b764 100644 --- a/cmd/core/help/cmd_test.go +++ b/cmd/core/help/cmd_test.go @@ -161,9 +161,28 @@ func TestAddHelpCommands_Bad(t *testing.T) { cmd := newHelpCommand(t) require.NoError(t, cmd.Flags().Set("search", "zzzyyyxxx")) - err := cmd.RunE(cmd, nil) - require.Error(t, err) - assert.Contains(t, err.Error(), "no help topics matched") + out := captureOutput(t, func() { + err := cmd.RunE(cmd, nil) + require.Error(t, err) + assert.Contains(t, err.Error(), "no help topics matched") + }) + + assert.Contains(t, out, "browse") + assert.Contains(t, out, "core help") + assert.Contains(t, out, "core help search") + }) + + t.Run("missing topic without suggestions shows hints", func(t *testing.T) { + cmd := newHelpCommand(t) + + out := captureOutput(t, func() { + err := cmd.RunE(cmd, []string{"definitely-not-a-real-topic"}) + require.Error(t, err) + assert.Contains(t, err.Error(), "help topic") + }) + + assert.Contains(t, out, "browse") + assert.Contains(t, out, "core help") }) t.Run("missing search query", func(t *testing.T) { @@ -179,13 +198,6 @@ func TestAddHelpCommands_Bad(t *testing.T) { assert.Contains(t, err.Error(), "help search query is required") }) - t.Run("missing topic", func(t *testing.T) { - cmd := newHelpCommand(t) - err := cmd.RunE(cmd, []string{"definitely-not-a-real-topic"}) - require.Error(t, err) - assert.Contains(t, err.Error(), "help topic") - }) - t.Run("missing topic shows suggestions when available", func(t *testing.T) { query := searchableHelpQuery(t) -- 2.45.3