From 42cdc937c867f5e35c75534f55caea51c60d388a Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Mon, 26 Jan 2026 01:12:37 +0000 Subject: feat(cli): Add bookmark search command (#2426) * feat(cli): Add search subcommand to bookmarks Add a new search subcommand that uses the searchBookmarks API endpoint. The command supports: - Full-text search with advanced query matchers (tag:, is:, list:, etc.) - Pagination with --all flag to fetch all results - Sorting by relevance, ascending, or descending order - Optional full content inclusion with --include-content - Configurable result limit per page Example usage: bookmarks search "is:fav tag:important" bookmarks search "kotlin" --sort-order desc --limit 20 bookmarks search "title:api" --include-content --all * fixes + format --------- Co-authored-by: Claude --- apps/cli/src/commands/bookmarks.ts | 89 +++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 11 deletions(-) (limited to 'apps/cli/src/commands/bookmarks.ts') diff --git a/apps/cli/src/commands/bookmarks.ts b/apps/cli/src/commands/bookmarks.ts index 021e344f..e2e8efb6 100644 --- a/apps/cli/src/commands/bookmarks.ts +++ b/apps/cli/src/commands/bookmarks.ts @@ -29,18 +29,10 @@ type Bookmark = Omit & { }; function normalizeBookmark(bookmark: ZBookmark): Bookmark { - const ret = { + return { ...bookmark, tags: bookmark.tags.map((t) => t.name), }; - - if (ret.content.type == BookmarkTypes.LINK && ret.content.htmlContent) { - if (ret.content.htmlContent.length > 10) { - ret.content.htmlContent = - ret.content.htmlContent.substring(0, 10) + "... "; - } - } - return ret; } function printBookmark(bookmark: ZBookmark) { @@ -151,10 +143,15 @@ bookmarkCmd .command("get") .description("fetch information about a bookmark") .argument("", "The id of the bookmark to get") - .action(async (id) => { + .option( + "--include-content", + "include full bookmark content in results", + false, + ) + .action(async (id, opts) => { const api = getAPIClient(); await api.bookmarks.getBookmark - .query({ bookmarkId: id }) + .query({ bookmarkId: id, includeContent: opts.includeContent }) .then(printBookmark) .catch(printError(`Failed to get the bookmark with id "${id}"`)); }); @@ -254,6 +251,11 @@ bookmarkCmd false, ) .option("--list-id ", "if set, only items from that list will be fetched") + .option( + "--include-content", + "include full bookmark content in results", + false, + ) .action(async (opts) => { const api = getAPIClient(); @@ -262,6 +264,7 @@ bookmarkCmd listId: opts.listId, limit: MAX_NUM_BOOKMARKS_PER_PAGE, useCursorV2: true, + includeContent: opts.includeContent, }; try { @@ -281,6 +284,70 @@ bookmarkCmd } }); +bookmarkCmd + .command("search") + .description("search bookmarks using query matchers") + .argument( + "", + "the search query (supports matchers like tag:name, is:fav, etc.)", + ) + .option( + "--limit ", + "number of results per page", + (val) => parseInt(val, 10), + 50, + ) + .option( + "--sort-order ", + "sort order for results", + (val) => { + if (val !== "relevance" && val !== "asc" && val !== "desc") { + throw new Error("sort-order must be one of: relevance, asc, desc"); + } + return val; + }, + "relevance", + ) + .option( + "--include-content", + "include full bookmark content in results", + false, + ) + .option("--all", "fetch all results (paginate through all pages)", false) + .action(async (query, opts) => { + const api = getAPIClient(); + + const request = { + text: query, + limit: opts.limit, + sortOrder: opts.sortOrder as "relevance" | "asc" | "desc", + includeContent: opts.includeContent, + }; + + try { + let resp = await api.bookmarks.searchBookmarks.query(request); + let results: ZBookmark[] = resp.bookmarks; + + // If --all flag is set, fetch all pages + if (opts.all) { + while (resp.nextCursor) { + resp = await api.bookmarks.searchBookmarks.query({ + ...request, + cursor: resp.nextCursor, + }); + results = [...results, ...resp.bookmarks]; + } + } + + printObject(results.map(normalizeBookmark), { maxArrayLength: null }); + } catch (error) { + printStatusMessage(false, "Failed to search bookmarks"); + if (error instanceof Error) { + printStatusMessage(false, error.message); + } + } + }); + bookmarkCmd .command("delete") .description("delete a bookmark") -- cgit v1.2.3-70-g09d2