Skip to content

feat(raycast): add server-backed search#567

Merged
JSONbored merged 3 commits into
JSONbored:mainfrom
YB0y:feat/raycast-server-backed-search
Jun 1, 2026
Merged

feat(raycast): add server-backed search#567
JSONbored merged 3 commits into
JSONbored:mainfrom
YB0y:feat/raycast-server-backed-search

Conversation

@YB0y

@YB0y YB0y commented May 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add server-backed Raycast search using /api/registry/search.
  • Preserve cached/static feed fallback when API search fails or is unavailable.
  • Add strict search response parsing, category-aware search, debounced queries, and pagination.
  • Add focused Raycast tests for API search parsing, malformed response handling, and local fallback filtering.

Closes #489
Refs #557

Quality Evidence

  • Changed routes/components/endpoints/tools: Raycast registry command, feed parsing helpers, runtime fetch helpers, Raycast tests.
  • Expected behavior: typing in Search HeyClaude fetches ranked API results; category commands search within their category; cached/static feed results remain usable offline.
  • Important edge cases or invariants: malformed search responses are rejected; favorites stay local; extension remains read-only and uses public HeyClaude endpoints only.
  • Backward compatibility notes: existing static feed loading, detail loading, favorites, copy/paste/open actions, and category commands are preserved.
  • Screenshots for frontend/page/UI changes:
    • Desktop: attached
    • Mobile: No mobile impact; Raycast is a macOS desktop extension.
  • Accessibility notes for UI changes: reuses Raycast native List, Detail, Dropdown, and ActionPanel components.
  • Focused tests or reason tests are not practical: focused Raycast parser/runtime/fallback tests were added.

Validation

  • npm test from integrations/raycast
  • npm run lint from integrations/raycast
  • npm run build from integrations/raycast
  • pnpm validate:raycast-feed
  • pnpm build
  • git diff --check

Notes

  • Please attach 2 desktop screenshots: one showing search results for a query like context, and one showing a selected result detail pane.
image

@YB0y YB0y requested a review from JSONbored as a code owner May 28, 2026 17:59
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 035ee996-ad25-4afe-931d-eaaa9ca89228

📥 Commits

Reviewing files that changed from the base of the PR and between 898522d and 1b72a7c.

📒 Files selected for processing (4)
  • integrations/raycast/src/feed.ts
  • integrations/raycast/src/registry-command.tsx
  • integrations/raycast/src/runtime.ts
  • integrations/raycast/test/feed.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • integrations/raycast/src/feed.ts
  • integrations/raycast/src/registry-command.tsx
  • integrations/raycast/test/feed.test.ts
📜 Recent review details
🔇 Additional comments (2)
integrations/raycast/src/runtime.ts (2)

13-23: LGTM!


235-258: Nicely done — this slots right into the existing fetch-helper family.

I really like how fetchRegistrySearch mirrors the shape of fetchRegistryManifestSnapshot (Lines 83-99) and fetchFeedPayload (Lines 155-166): same injectable fetchFn ?? fetch, same accept: application/json header, same non-OK guard. That consistency makes the module easy to reason about. Delegating validation to parseRegistrySearch keeps the strict-parsing contract in one place, and letting parse/JSON errors propagate is the right call since loadMoreSearchResults already handles them at the call site.

One thing worth keeping on your radar (no change needed here, since it's consistent with the rest of the file): none of these helpers set an AbortSignal/timeout, so a hung connection on the request thread would just wait on the platform default. If you ever revisit network resilience for the Raycast commands, adding a shared timeout across all these fetchers would be the natural spot — but that's a follow-up, not a blocker for this PR.


📝 Walkthrough

Summary by CodeRabbit

Release Notes

  • New Features

    • Added server-backed search functionality with debouncing and pagination support
    • Implemented "Load More Search Results" action for incremental result fetching
    • Added search filtering with tokenized, case-insensitive text matching across entry fields
  • Tests

    • Extended test coverage for registry search operations and result parsing

Walkthrough

Adds server-backed registry search: URL/types, strict parsing and normalization, runtime fetcher, debounced command orchestration with pagination, UI wiring to show server results or local fallback, and tests plus tokenized local filtering.

Changes

Server-backed registry search

Layer / File(s) Summary
Registry search schema and parsing
integrations/raycast/src/feed.ts
Introduces REGISTRY_SEARCH_URL, ParsedRegistrySearch and RegistrySearchUrlOptions types, registrySearchUrl builder, normalizeRegistrySearchEntry/parseRegistrySearch with strict validation, and filterEntriesBySearchText tokenized filtering.
Runtime API fetcher
integrations/raycast/src/runtime.ts
Adds fetchRegistrySearch which builds request URLs, performs fetch with optional injected fetchFn, rejects non-OK responses, and returns parsed search payloads.
Command state and search helpers
integrations/raycast/src/registry-command.tsx
Adds ServerSearchState, SEARCH_PAGE_SIZE, serverSearchCategory mapper, and createEmptyServerSearchState; wires controlled searchText and serverSearch React state.
Debounced search triggering and pagination
integrations/raycast/src/registry-command.tsx
Implements 300ms debounced server search with cancellation, updates serverSearch (loading/ready/failed), adds loadMoreSearchResults pagination with staleness guards, and computes visibleEntries switching between server and local results.
UI updates for server search results
integrations/raycast/src/registry-command.tsx
Wires the search bar to searchText, disables built-in filtering during server search, updates List.isLoading and empty-state messaging, renders visibleEntries, adds conditional "Load More Search Results" action, and gates empty view while loading.
Test coverage for search functionality
integrations/raycast/test/feed.test.ts
Adds tests for parseRegistrySearch (mapping and malformed rejection), registrySearchUrl (normalized URL construction), filterEntriesBySearchText (token matching and edge cases), and async fetchRegistrySearch (request URL, parsing, and 503/malformed rejection).

Sequence Diagram(s)

sequenceDiagram
    participant User as User Input
    participant Command as Registry Command
    participant FetchFunc as fetchRegistrySearch
    participant Runtime as fetch (HTTP)
    participant Parser as parseRegistrySearch
    participant UI as Raycast UI

    User->>Command: Type search query
    Command->>Command: Debounce 300ms
    Command->>FetchFunc: Call with query/category
    FetchFunc->>FetchFunc: Build registrySearchUrl
    FetchFunc->>Runtime: HTTP GET /api/registry/search
    Runtime-->>FetchFunc: JSON response
    FetchFunc->>Parser: Parse response body
    Parser-->>FetchFunc: ParsedRegistrySearch
    FetchFunc-->>Command: Return results + nextOffset
    Command->>Command: Update serverSearch state
    Command->>UI: Render visibleEntries
    UI-->>User: Show server-ranked results
    User->>Command: Click "Load More"
    Command->>FetchFunc: Call with offset
    FetchFunc->>Runtime: HTTP GET with offset
    Runtime-->>FetchFunc: Next page JSON
    FetchFunc-->>Command: Append to results
    Command->>UI: Re-render with more entries
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

feature, contributor:verified, pr:verified

Suggested reviewers

  • JSONbored

Poem

🔎 New search wakes the static feed from sleep,
A debounce pause to let the queries sweep,
Pages come back, parsed clean and bright,
Fallback stays ready if the server's not right,
More results, one click—discoveries to keep.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Docstring Coverage ❌ Error Docstring coverage is 0.00% which is insufficient. The required threshold is 90.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(raycast): add server-backed search' clearly and concisely summarizes the main feature being added—server-backed search for the Raycast extension.
Description check ✅ Passed The PR description covers the required sections: summary of changes, validation steps completed, quality evidence with implementation details and backward compatibility notes, and supporting documentation with screenshots.
Linked Issues check ✅ Passed All acceptance criteria from issue #489 are met: API-backed search via /api/registry/search is implemented [feed.ts, runtime.ts], cached/static fallback is preserved [registry-command.tsx], read-only constraint is maintained, and comprehensive tests cover API search, malformed responses, and offline behavior [feed.test.ts].
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing server-backed search: registry search URL/parsing/filtering helpers, runtime fetch function, command state/pagination logic, and comprehensive tests—no extraneous modifications detected.
Security Pattern Review ✅ Passed Safe URL construction via URLSearchParams, strict response parsing with schema validation, no hardcoded secrets or XSS vulnerabilities, input properly validated with type guards.
Client/Server Boundary Validation ✅ Passed PR modifies only Raycast extension files, not Next.js components or API routes. The check is not applicable to this PR scope.
Logging Standards Compliance ✅ Passed Check is not applicable to this PR—it's scoped to apps/web/src and packages/web-runtime/src, but PR only changes integrations/raycast/. Check does not apply.
✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@integrations/raycast/src/feed.ts`:
- Around line 652-658: The current local fallback tokenization can yield
tokens=[] for punctuation-only but non-empty searchText, causing every entry to
match; after computing tokens from query in the feed filter, add a guard: if
query is non-empty and tokens.length === 0 then return an empty array (or
no-results) instead of continuing to match all entries; modify the block where
query, tokens, and entries are used (referencing variables searchText, query,
tokens, entries) to short-circuit in that case so punctuation-only queries
produce no results.
- Around line 243-244: The pagination params are dropped because the code uses
truthy checks for options.limit and options.offset; change those checks in
registrySearchUrl to test for undefined/null (e.g., if (options.limit !==
undefined) and if (options.offset !== undefined)) so that 0 values are
preserved, and still call url.searchParams.set("limit", String(options.limit)) /
set("offset", String(options.offset)) when present.

In `@integrations/raycast/src/registry-command.tsx`:
- Around line 311-347: The loadMoreSearchResults function needs to ignore stale
responses by capturing a request key (e.g., const requestKey =
`${normalizedSearchText}::${searchCategory ?? ""}`) before calling
fetchRegistrySearch and then, before any state mutation in both the success and
catch branches, verify the current active key still equals requestKey; only then
merge entries/update total/nextOffset/status/error and isLoading. Use the same
requestKey check around the setServerSearch calls so an in-flight response for
an old query/category cannot append into a newer active search.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: dcc83308-1c01-454b-b6fe-b1a1e2bc471a

📥 Commits

Reviewing files that changed from the base of the PR and between 3fab80f and 898522d.

📒 Files selected for processing (4)
  • integrations/raycast/src/feed.ts
  • integrations/raycast/src/registry-command.tsx
  • integrations/raycast/src/runtime.ts
  • integrations/raycast/test/feed.test.ts
📜 Review details
🔇 Additional comments (2)
integrations/raycast/src/runtime.ts (1)

13-20: LGTM!

Also applies to: 235-258

integrations/raycast/test/feed.test.ts (1)

9-9: LGTM!

Also applies to: 22-22, 28-30, 38-38, 244-297, 350-365, 538-547, 564-569, 763-820

Comment thread integrations/raycast/src/feed.ts Outdated
Comment thread integrations/raycast/src/feed.ts
Comment thread integrations/raycast/src/registry-command.tsx

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action: request changes

  • The server-backed search direction fits #489, and the Raycast checks are green.
  • Three current issues still need fixing before merge:
  • Preserve explicit limit=0 / offset=0 in registrySearchUrl; the current truthy checks drop those values.
  • Return no local fallback results for punctuation-only non-empty search text; current empty-token behavior can match every entry.
  • Guard loadMoreSearchResults against stale responses before appending or setting errors so an old query/category cannot mutate a newer search.
  • Please keep the fix narrow and rerun the Raycast test/feed lane.

@YB0y YB0y force-pushed the feat/raycast-server-backed-search branch from 1f2d20e to 313aff7 Compare May 28, 2026 23:52
Add server-backed registry search for the Raycast extension with local
fallback filtering. Preserve explicit limit=0/offset=0 in the search URL,
return no local fallback matches for punctuation-only search text, and
guard load-more pagination against stale query/category responses.
@coderabbitai coderabbitai Bot requested a review from JSONbored May 28, 2026 23:53
@YB0y YB0y force-pushed the feat/raycast-server-backed-search branch from 313aff7 to 1b72a7c Compare May 28, 2026 23:53
@YB0y

YB0y commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

Hi @JSONbored thanks for reviewing. Please review again.

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@YB0y the prior server-search blockers look fixed, but the PR is currently conflicted.

  • Resolve the current merge conflicts against main.
  • Keep the fixes for explicit zero pagination params, punctuation-only local fallback search, and stale-response protection.
  • Re-run the Raycast checks after conflict resolution.
  • Expected validation: npm test from integrations/raycast, npm run lint, npm run build, pnpm validate:raycast-feed, and git diff --check.
  • No additional server-search behavior changes are requested from my review if the conflict-resolved branch stays green.

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Jun 1, 2026
@YB0y

YB0y commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

Resolved the merge conflict against current main and kept the existing server-search fixes for explicit zero pagination params, punctuation-only local fallback search, and stale load-more responses. Reran the requested Raycast validation: npm test, npm run lint, npm run build, pnpm validate:raycast-feed, and git diff --check all pass.

@JSONbored JSONbored dismissed their stale review June 1, 2026 06:47

@YB0y thanks, this looks ready for merge.

A few notes:

  • The current branch is clean against origin/main, required Raycast/worktree checks are green, and git diff --check is clean.
  • The previous server-search blockers look addressed: explicit limit=0 / offset=0 are preserved, punctuation-only fallback search returns no results, and load-more responses are guarded against stale query/category state.
  • No requested changes from me.
@JSONbored JSONbored merged commit 7fcbdc1 into JSONbored:main Jun 1, 2026
18 checks passed
@JSONbored JSONbored added the gittensor:priority Gittensor-scored priority contributions. PRs and issues with this label score a 1.75x multiplier. label Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:priority Gittensor-scored priority contributions. PRs and issues with this label score a 1.75x multiplier. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(raycast): add server-backed search mode

2 participants