From 9881c22c311a7aad562d427adea32e2ca01a2cab Mon Sep 17 00:00:00 2001 From: chruffins <23645059+chruffins@users.noreply.github.com> Date: Tue, 13 Oct 2026 22:55:09 +0000 Subject: [PATCH 1/2] Accept -o json on kernel search commands Search commands always print JSON, but they rejected the -o flag that other commands accept, so scripts piping through jq got an error on stderr instead of JSON. Register the shared output flag on search, get, providers, and contents, and validate it before any request is sent. --- cmd/search.go | 8 ++++++++ cmd/search_test.go | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/cmd/search.go b/cmd/search.go index 6184282b..3539afd0 100644 --- a/cmd/search.go +++ b/cmd/search.go @@ -69,6 +69,10 @@ func newSearchCommand() *cobra.Command { contents.Flags().String("content-browser-mode", "", "Browser retrieval mode: curl or render") contents.MarkFlagsMutuallyExclusive("result-ids", "limit") contents.MarkFlagsOneRequired("result-ids", "limit") + addJSONOutputFlag(cmd) + addJSONOutputFlag(get) + addJSONOutputFlag(providers) + addJSONOutputFlag(contents) cmd.AddCommand(get, providers, contents) return cmd } @@ -211,6 +215,10 @@ func validateSearchQuery(query string) error { } func executeSearchRequest(cmd *cobra.Command, method, path string, body json.RawMessage) error { + output, _ := cmd.Flags().GetString("output") + if err := validateJSONOutput(output); err != nil { + return err + } client := getKernelClient(cmd) var response json.RawMessage var opts []option.RequestOption diff --git a/cmd/search_test.go b/cmd/search_test.go index c6dc7dd9..c9aae4f1 100644 --- a/cmd/search_test.go +++ b/cmd/search_test.go @@ -74,6 +74,8 @@ func TestSearchReadCommands(t *testing.T) { {[]string{"get", "srch_test"}, "/search/srch_test", "", `{"id":"srch_test","results":[]}`}, {[]string{"providers"}, "/search/providers", "", `[]`}, {[]string{"providers", "--slug", "exa&other=1"}, "/search/providers", "slug=exa%26other%3D1", `[]`}, + {[]string{"get", "srch_test", "-o", "json"}, "/search/srch_test", "", `{"id":"srch_test","results":[]}`}, + {[]string{"providers", "-o", "json"}, "/search/providers", "", `[]`}, } { t.Run(strings.Join(tc.args, " "), func(t *testing.T) { stdout, err := executeSearchCommand(t, func(w http.ResponseWriter, r *http.Request) { @@ -99,6 +101,7 @@ func TestSearchContents(t *testing.T) { want string }{ {"limit", []string{"--limit", "3"}, `{"limit":3}`}, + {"limit with json output", []string{"--limit", "3", "-o", "json"}, `{"limit":3}`}, {"result ids", []string{"--result-ids", "res_2,res_1", "--timeout-ms", "30000"}, `{"result_ids":["res_2","res_1"],"timeout_ms":30000}`}, {"content options", []string{"--limit", "1", "--content-source", "browser", "--content-format", "text", "--content-max-chars", "500", "--content-max-age-hours", "0", "--content-timeout-ms", "5000", "--content-browser-id", "br_1", "--content-browser-mode", "render"}, `{"limit":1,"content":{"source":"browser","format":"text","max_chars":500,"max_age_hours":0,"timeout_ms":5000,"browser":{"browser_id":"br_1","mode":"render"}}}`}, @@ -127,6 +130,7 @@ func TestSearchInvalidInput(t *testing.T) { for _, args := range [][]string{ {}, {" "}, {strings.Repeat("x", 2049)}, {"a", "b"}, {"test", "--provider", ""}, {"test", "--max-results", "0"}, {"test", "--max-results", "101"}, + {"test", "-o", "yaml"}, {"get", "srch_test", "-o", "yaml"}, {"contents", "srch_test", "--limit", "1", "-o", "yaml"}, {"--request", "null"}, {"--request", "[]"}, {"--request", "{"}, {"--request", `{}`}, {"--request", `{"query":1}`}, {"test", "--request", `{"query":"test"}`}, {"--request", `{}`, "--provider", "exa"}, {"--request", `{}`, "--max-results", "5"}, {"--request-file", "request.json"}, From 0187fdababae79e632116bcf58a594a873727974 Mon Sep 17 00:00:00 2001 From: chruffins <23645059+chruffins@users.noreply.github.com> Date: Tue, 13 Oct 2026 23:02:34 +0000 Subject: [PATCH 2/2] Document the content max chars range in search help --- README.md | 2 +- cmd/search.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8bf3edc5..f8fa9cdb 100644 --- a/README.md +++ b/README.md @@ -1481,7 +1481,7 @@ Automated authentication for web services. The `run` command orchestrates the fu - `--show-content` - Print the extracted content text for each result (implies `--content`) - `--content-source ` - Retrieval source: `auto`, `provider`, or `browser` - `--content-format ` - Extracted content format: `markdown` or `text` - - `--content-max-chars ` - Per-result Unicode character limit after extraction + - `--content-max-chars ` - Per-result Unicode character limit after extraction (100–100000; default 10000) - `--content-max-age-hours ` - Maximum acceptable age of cached page content; `0` forces a live fetch - `--content-timeout-ms ` - Per-result retrieval deadline - `--content-browser-id ` - Retrieve through an existing browser session (requires `--content-source browser`) diff --git a/cmd/search.go b/cmd/search.go index 3539afd0..1e6b15d2 100644 --- a/cmd/search.go +++ b/cmd/search.go @@ -62,7 +62,7 @@ func newSearchCommand() *cobra.Command { contents.Flags().Int("timeout-ms", 0, "Overall deadline across all selected results in milliseconds (1000–120000; default 60000)") contents.Flags().String("content-source", "", "Content source: auto, provider, or browser (default auto)") contents.Flags().String("content-format", "", "Content format: markdown or text") - contents.Flags().Int("content-max-chars", 0, "Per-result Unicode character limit after extraction") + contents.Flags().Int("content-max-chars", 0, "Per-result Unicode character limit after extraction (100–100000; default 10000)") contents.Flags().Int("content-max-age-hours", 0, "For source auto, maximum age of retained provider content; 0 fetches every result through a browser") contents.Flags().Int("content-timeout-ms", 0, "Per-result deadline in milliseconds, including capacity acquisition, retrieval, and extraction") contents.Flags().String("content-browser-id", "", "Existing browser session to retrieve through (requires source auto or browser)")