fix(help): add recovery hints to help lookups

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-02 10:10:56 +00:00
parent f71bdb3bf4
commit 7bf060986d
2 changed files with 34 additions and 10 deletions

View file

@ -2,6 +2,7 @@ package help
import ( import (
"bufio" "bufio"
"fmt"
"strings" "strings"
"forge.lthn.ai/core/cli/pkg/cli" "forge.lthn.ai/core/cli/pkg/cli"
@ -38,7 +39,10 @@ func AddHelpCommands(root *cli.Command) {
return suggestErr return suggestErr
} }
cli.Blank() 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]) 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 { func renderSearchResults(results []*gohelp.SearchResult, query string) error {
if len(results) == 0 { if len(results) == 0 {
renderHelpHint(query)
return cli.Err("no help topics matched %q", query) return cli.Err("no help topics matched %q", query)
} }
@ -102,6 +107,13 @@ func renderSearchResults(results []*gohelp.SearchResult, query string) error {
return nil 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 { func renderTopicList(topics []*gohelp.Topic) error {
if len(topics) == 0 { if len(topics) == 0 {
return cli.Err("no help topics available") return cli.Err("no help topics available")

View file

@ -161,9 +161,28 @@ func TestAddHelpCommands_Bad(t *testing.T) {
cmd := newHelpCommand(t) cmd := newHelpCommand(t)
require.NoError(t, cmd.Flags().Set("search", "zzzyyyxxx")) require.NoError(t, cmd.Flags().Set("search", "zzzyyyxxx"))
err := cmd.RunE(cmd, nil) out := captureOutput(t, func() {
require.Error(t, err) err := cmd.RunE(cmd, nil)
assert.Contains(t, err.Error(), "no help topics matched") 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) { 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") 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) { t.Run("missing topic shows suggestions when available", func(t *testing.T) {
query := searchableHelpQuery(t) query := searchableHelpQuery(t)