Skip to content

feat: evaluate fuzzy search scoring libraries to replace custom implementation #348

@kexi

Description

@kexi

Summary

Currently, we have a custom fuzzy matching and scoring implementation in packages/core/src/utils/fuzzy.ts. While it works for our use case, it may benefit from being replaced by a well-tested, community-maintained library that offers better scoring quality and performance.

Current Implementation

Our custom fuzzyMatch() function (packages/core/src/utils/fuzzy.ts) performs subsequence matching with the following scoring:

  • Consecutive match bonus: square of consecutive length (3 consecutive = +9)
  • Word boundary bonus: +10 when matching after /, -, _
  • Start bonus: +15 when first match is at position 0
  • Gap penalty: -1 per skipped character
  • Tail penalty: -0.5 per unused character after last match

~110 lines of code total. It's functional but may not produce optimal rankings for worktree paths (e.g., feature/auth-login, bugfix/header-style).

Candidate Libraries

Library Bundle Size Approach Notes
Fuse.js ~17 kB min Bitap algorithm Most popular, rich features, configurable scoring
uFuzzy ~7 kB min Multi-pass (exact → fuzzy) Very fast, designed for large lists, good scoring
fzf-for-js ~8 kB min fzf v2 algorithm port Familiar scoring for fzf users, path-aware
QuickScore ~5 kB min Quicksilver algorithm Excellent for path/filename matching
microfuzz ~1 kB min Simple fuzzy Very lightweight, minimal features

Evaluation Criteria

  • Bundle size: vibe is a CLI tool, so size is less critical than for web apps, but smaller is still preferred
  • Performance: Must handle typical worktree lists (10-100 items) without noticeable delay
  • Scoring quality: Path-aware scoring is important — should rank well for patterns like feature/foo, bugfix/bar-baz
  • Path separator handling: Should understand /, -, _ as word boundaries (critical for worktree names)
  • TypeScript support: First-class TypeScript types preferred
  • Maintenance: Actively maintained, reasonable issue response time
  • Match highlighting: Ability to return match positions for potential UI highlighting
  • Dependency count: Zero or minimal transitive dependencies preferred

Context

  • The fuzzy matching is used in the jump command to match user input against worktree names
  • Typical input: short partial strings (2-10 chars) matched against worktree branch names
  • Current implementation: fuzzyMatch() + FUZZY_MATCH_MIN_LENGTH (3 chars minimum)

Next Steps

  1. Benchmark candidate libraries against our current implementation with real worktree path data
  2. Compare scoring quality for common worktree naming patterns
  3. Select the best fit and create a follow-up PR to replace the custom implementation (or decide to keep the current one if no library provides clear benefits)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions