Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "keenable-cli"
version = "0.2.1"
version = "0.2.2"
edition = "2024"
description = "Keenable CLI — authenticate, manage API keys, configure MCP, and search the web"
authors = ["grigorevp <grigoryev.pete@gmail.com>"]
Expand Down
4 changes: 4 additions & 0 deletions src/commands/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ pub async fn search(
mode: Option<&str>,
filters: SearchFilters,
snippet_max_length: Option<u64>,
max_results: Option<u64>,
human: bool,
api_key: Option<&str>,
) {
Expand Down Expand Up @@ -311,6 +312,9 @@ pub async fn search(
if let Some(n) = snippet_max_length {
body["snippet_max_length"] = json!(n);
}
if let Some(n) = max_results {
body["max_results"] = json!(n);
}
// Merge filter fields into body
if let Value::Object(filter_map) = filters.to_json()
&& let Value::Object(ref mut body_map) = body
Expand Down
8 changes: 7 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ enum Commands {

/// Search the web (outputs YAML by default, use -p for pretty output)
#[command(
after_help = "Works without login (free tier). Log in for higher rate limits.\n\nExamples:\n keenable search \"rust async\" YAML output (for agents)\n keenable search \"rust async\" -p Pretty output (for humans)\n keenable search \"AI news\" --site techcrunch.com Restrict to site\n keenable search \"dodgers braves\" --published-after 2026-01-01 Date filter (YYYY-MM-DD)\n keenable search \"AI news\" --acquired-after 7d Relative date (min, h, d, mo, y)\n keenable search \"AI news\" --acquired-after 2026-01-15T10:30:00Z ISO 8601 datetime\n keenable search \"rust async\" --snippet-max-length 2000 Longer snippets (180-10000)\n keenable search \"AI news\" --query-time 2026-01-01T00:00:00Z Point-in-time search\n keenable search \"rust async\" --api-key keen_***_***** Use a specific API key"
after_help = "Works without login (free tier). Log in for higher rate limits.\n\nExamples:\n keenable search \"rust async\" YAML output (for agents)\n keenable search \"rust async\" -p Pretty output (for humans)\n keenable search \"AI news\" --site techcrunch.com Restrict to site\n keenable search \"dodgers braves\" --published-after 2026-01-01 Date filter (YYYY-MM-DD)\n keenable search \"AI news\" --acquired-after 7d Relative date (min, h, d, mo, y)\n keenable search \"AI news\" --acquired-after 2026-01-15T10:30:00Z ISO 8601 datetime\n keenable search \"rust async\" --snippet-max-length 2000 Longer snippets (180-10000)\n keenable search \"rust async\" --max-results 25 More results (1-50, default 10)\n keenable search \"AI news\" --query-time 2026-01-01T00:00:00Z Point-in-time search\n keenable search \"rust async\" --api-key keen_***_***** Use a specific API key"
)]
Search {
/// Search query
Expand Down Expand Up @@ -171,6 +171,10 @@ enum Commands {
#[arg(long = "snippet-max-length")]
snippet_max_length: Option<u64>,

/// Maximum number of results (API accepts 1-50, default 10)
#[arg(long = "max-results")]
max_results: Option<u64>,

/// Point-in-time search: only pages available on or before this timestamp (YYYY-MM-DD, ISO 8601, or relative e.g. 7d, 3mo, 1y)
#[arg(long)]
query_time: Option<String>,
Expand Down Expand Up @@ -304,6 +308,7 @@ async fn main() {
published_after,
published_before,
snippet_max_length,
max_results,
query_time,
pretty,
api_key,
Expand All @@ -321,6 +326,7 @@ async fn main() {
mode.as_deref(),
filters,
snippet_max_length,
max_results,
pretty,
api_key.as_deref(),
)
Expand Down
16 changes: 16 additions & 0 deletions tests/e2e/test_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ def test_snippet_max_length_out_of_range(kn):
assert "snippet_max_length" in data["message"]


def test_max_results(kn):
few = kn("search", SEARCH_QUERY, "--max-results", "3").yaml()
many = kn("search", SEARCH_QUERY, "--max-results", "30").yaml()
assert len(results_of(few)) <= 3
# A dropped param would give both runs the default count (10).
assert len(results_of(many)) > 10


def test_max_results_out_of_range(kn):
res = kn("search", SEARCH_QUERY, "--max-results", "51")
assert res.code == 1
data = res.yaml()
assert data["error"] == "Invalid parameter"
assert "max_results" in data["message"]


# --- 2.2 modes ---

def test_mode_realtime(kn):
Expand Down
Loading