npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@mosetta/ide-plugin-search

v0.0.14

Published

Shift+Shift: one window over files, symbols, scripts, terminals and settings, with a preview and typed tags.

Readme

Search everywhere

@mosetta/ide-plugin-search · Shift+Shift: one window over files, symbols, scripts, terminals and settings, with a preview and typed tags.

What it does

Press Shift twice and a window opens over the panels: a field, the results in sections, and a preview of the selected one. It searches everything the plugins have registered — files and TypeScript symbols from the project index, npm scripts, open terminals, recent files, and every setting.

  • Instant. The index lives in the daemon's memory and is kept current by events; a keystroke never waits for the disk.
  • Typed tags narrow the search by kind: ts function fit finds functions whose name fits fit; npm dev finds scripts; a setting's section is a tag too.
  • Matches the way you type: a query lands on the starts of words, so dccf finds DesktopCreditCardForm; and a query typed in the Russian layout by mistake is read in the English one too.
  • Enter does the obvious thing for each kind: a file opens, a script runs, a terminal comes forward, a setting opens in the settings window.
  • Honest about coverage. If the index skipped files — too many, too large — the window says so instead of showing a list that looks complete.

Keys

| Command | macOS | Windows and Linux | |---|---|---| | search.everywhere | Shift Shift, Cmd+P, Cmd+2 | Shift Shift, Ctrl+P, Ctrl+Alt+2 (browser), Ctrl+2 (desktop) |

Arrows move, Enter opens, Escape closes.

Settings

Section index in settings.json:

| Key | Default | What it does | |---|---|---| | enabled | true | Build the index when a project opens. | | maxResults | 50 | How many hits to show; the window says when there were more. | | recentFiles | 15 | How many recent files to offer before anything is typed. | | symbolsMaxKb | 512 | Files larger than this are not parsed for symbols. |

Screenshots and demos

Search everywhere with files, symbols and a preview

Typing a query, then narrowing it with a tag

Watch the video · Try it in the browser

Using it from another plugin

The search window is a commons: it declares three registry keys, and each kind of hit is brought by the plugin that owns it.

| Key | What an entry is | |---|---| | search.source | id, a kind, and find({ term, tags, limit }) returning hits (kind, label, path, score, matches, and optionally line, detail, tags, id). Optionally tags() — the tags this source understands — and note(), a line to show under the section. | | search.opener | kind and open(hit): what Enter does with a hit of that kind. Without one, the hit's file is opened. | | search.icon | kind and icon(hit): the icon on a row. |

A source of your own, matched the same way everything else is:

import SearchPlugin from '@mosetta/ide-plugin-search';

this.ide.registry('search.source').add({
  id: 'notes',
  kind: 'note',
  find: ({ term, limit }: { term: string; limit: number }) => {
    const search = this.ide.getPlugin(SearchPlugin);
    const folded = search.textIndex.fold(term);
    return this.notes.value
      .map((note) => {
        const hit = search.matcher.match(search.textIndex.of(note.title), folded);
        return hit && { kind: 'note', label: note.title, path: note.file, score: hit.score, matches: hit.positions };
      })
      .filter(Boolean)
      .slice(0, limit);
  },
});

this.ide.registry('search.opener').add({
  kind: 'note',
  open: (hit: { path: string }) => this.show(hit.path),
});

Ask the index directly — the same answer the window gets:

const { hits, total } = await this.ide.getPlugin(SearchPlugin).find('flock', 20, ['file']);

Index kinds from the daemon. The server half is extensible too: a plugin's server half can teach the index a new kind of hit parsed from files, the way the npm scripts plugin reads package.json:

import SearchServer from '@mosetta/ide-plugin-search/server';

this.ide.getPlugin(SearchServer).find({
  kind: 'npm',
  wants: (path) => path.endsWith('package.json'),
  finds: (path, text) => Object.keys(JSON.parse(text).scripts ?? {}).map((name) => ({ label: name, id: name })),
});