Reject single bare word as implicit note shorthand
Single unrecognized words now print an error with usage hint instead of being submitted as a note. Prevents typos from creating junk notes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
+5
-2
@@ -38,6 +38,9 @@ var rootCmd = &cobra.Command{
|
|||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return cmd.Help()
|
return cmd.Help()
|
||||||
}
|
}
|
||||||
|
if len(args) == 1 {
|
||||||
|
return fmt.Errorf("unknown command %q\nTo add a note, use: kb \"%s ...\" or pass multiple words", args[0], args[0])
|
||||||
|
}
|
||||||
note := strings.Join(args, " ")
|
note := strings.Join(args, " ")
|
||||||
tags, _ := cmd.Flags().GetString("tags")
|
tags, _ := cmd.Flags().GetString("tags")
|
||||||
client := api.NewClient()
|
client := api.NewClient()
|
||||||
@@ -48,8 +51,8 @@ var rootCmd = &cobra.Command{
|
|||||||
func init() {
|
func init() {
|
||||||
api.SetVersionInfo(Version, MinEngineVersion)
|
api.SetVersionInfo(Version, MinEngineVersion)
|
||||||
rootCmd.Version = Version
|
rootCmd.Version = Version
|
||||||
rootCmd.SetUsageTemplate(`Quick note taking:
|
rootCmd.SetUsageTemplate(`Quick note taking (must be more than one word):
|
||||||
kb "note text" [flags]
|
kb "note text here" [flags]
|
||||||
|
|
||||||
Normal usage:
|
Normal usage:
|
||||||
kb [command] [flags]{{if .HasAvailableSubCommands}}
|
kb [command] [flags]{{if .HasAvailableSubCommands}}
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRootCmd_SingleWordRejected(t *testing.T) {
|
||||||
|
rootCmd.SetArgs([]string{"infow"})
|
||||||
|
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
rootCmd.SetErr(&stderr)
|
||||||
|
|
||||||
|
err := rootCmd.Execute()
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected error for single bare word, got nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
errMsg := err.Error()
|
||||||
|
if !strings.Contains(errMsg, `unknown command "infow"`) {
|
||||||
|
t.Errorf("expected error to mention unknown command, got: %s", errMsg)
|
||||||
|
}
|
||||||
|
if !strings.Contains(errMsg, "multiple words") {
|
||||||
|
t.Errorf("expected error to suggest multiple words, got: %s", errMsg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRootCmd_MultipleWordsNotRejected(t *testing.T) {
|
||||||
|
rootCmd.SetArgs([]string{"remember", "to", "update", "dns"})
|
||||||
|
|
||||||
|
err := rootCmd.Execute()
|
||||||
|
// Will fail at API call (no server), but should NOT be the "unknown command" error
|
||||||
|
if err != nil && strings.Contains(err.Error(), "unknown command") {
|
||||||
|
t.Errorf("multi-word input should not be rejected as unknown command, got: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRootCmd_NoArgs_ShowsHelp(t *testing.T) {
|
||||||
|
rootCmd.SetArgs([]string{})
|
||||||
|
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
rootCmd.SetOut(&stdout)
|
||||||
|
|
||||||
|
err := rootCmd.Execute()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected no error for zero args, got: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
output := stdout.String()
|
||||||
|
if !strings.Contains(output, "Available Commands") {
|
||||||
|
t.Errorf("expected help output, got: %s", output)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,7 +70,7 @@ The client SHALL provide a `kb search <query>` command that sends the query to t
|
|||||||
|
|
||||||
### Requirement: Implicit note shorthand
|
### Requirement: Implicit note shorthand
|
||||||
|
|
||||||
The client SHALL treat bare string arguments (with no subcommand) as an implicit note. `kb "my note"` SHALL behave identically to submitting a note via `POST /api/v1/jobs`. All persistent flags (`--format`, `--engine`, `--api-key`) and the root `--tags` flag SHALL work with the shorthand form.
|
The client SHALL treat bare string arguments (with no subcommand) as an implicit note only when **more than one argument** is provided. `kb "my note"` SHALL behave identically to submitting a note via `POST /api/v1/jobs`. All persistent flags (`--format`, `--engine`, `--api-key`) and the root `--tags` flag SHALL work with the shorthand form. A single bare word SHALL be rejected with an error message.
|
||||||
|
|
||||||
#### Scenario: Quick note via bare argument
|
#### Scenario: Quick note via bare argument
|
||||||
- **WHEN** the user runs `kb "remember to update DNS"`
|
- **WHEN** the user runs `kb "remember to update DNS"`
|
||||||
@@ -92,6 +92,10 @@ The client SHALL treat bare string arguments (with no subcommand) as an implicit
|
|||||||
- **WHEN** the user runs `kb remember to update dns` (without quotes)
|
- **WHEN** the user runs `kb remember to update dns` (without quotes)
|
||||||
- **THEN** the client SHALL join all arguments into a single note string and submit it
|
- **THEN** the client SHALL join all arguments into a single note string and submit it
|
||||||
|
|
||||||
|
#### Scenario: Single bare word rejected
|
||||||
|
- **WHEN** the user runs `kb infow` (a single unrecognized word)
|
||||||
|
- **THEN** the client SHALL print to stderr: `Unknown command "infow". Run 'kb --help' for available commands.` followed by a hint about note usage, and exit with a non-zero code
|
||||||
|
|
||||||
#### Scenario: No interference with subcommands
|
#### Scenario: No interference with subcommands
|
||||||
- **WHEN** the user runs `kb search "query"` or any other existing subcommand
|
- **WHEN** the user runs `kb search "query"` or any other existing subcommand
|
||||||
- **THEN** the client SHALL route to the subcommand as before — the implicit note shorthand SHALL NOT interfere
|
- **THEN** the client SHALL route to the subcommand as before — the implicit note shorthand SHALL NOT interfere
|
||||||
|
|||||||
Reference in New Issue
Block a user