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

@elaraai/east-plugin

v1.0.98

Published

East's agent plugin runtime — the example index generator, the example search and its MCP tools, the search-first hooks and the Codex skill adapter — for a Claude Code or Codex plugin that builds on East's.

Readme

Shared East Agent Plugin Library

The common implementation used by east-claude-plugin and east-codex-plugin, published as @elaraai/east-plugin for a Claude Code or Codex plugin that builds on East's (see Building on East's plugin). It is not an agent plugin itself.

  • lib/: project detection, search, review and deduplication, daemon client, Python diagnostics, status, transcript helpers, the stdio LSP client, the search-first guidance and hooks (Claude Code's in search-hooks.ts, Codex's in codex-hook.ts), the Codex skill adapter (codex-skills.ts), and the plugin assembler (package.ts).
  • hooks/: common lifecycle and Claude tool adapters. Codex's one tool hook is east-codex-plugin/hooks/codex-tools.ts, over lib/codex-hook.ts and lib/codex-tools.ts (patch and shell normalization).
  • daemon/: TypeScript/TSX LSP, Python LSP launcher and resident diagnostics server.
  • mcp/: example search, retrieval, status and the real LSP bridge; the search and retrieval tools are example-tools.ts's, for any server.
  • skills/: the one skill catalog — the four plugin-native skills plus symlinks to the package-owned skills.
  • scripts/: the sole index generator, Python renderer, the assembler driver (package.ts) and CLI installation/update implementations.
  • index.json: the canonical generated corpus, the one committed artifact. Each assembled plugin ships a copy, and the published package ships it for a plugin that serves East's corpus beside its own.
  • marketplace/ (ignored): both plugins assembled as the hosts install them, east-claude-plugin/ and east-codex-plugin/, with marketplace files naming them — a local marketplace for Claude Code and Codex under the catalog's names (elaraai, elaraai-codex), so a maintainer points either name at the checkout or at the catalog.

Host runtime files are thin package re-exports, inlined by esbuild. They must not grow independent copies of shared behavior. hostText translates host-facing tool and skill names at the output boundary. The assembled plugins intentionally contain duplicated bytes so an installed plugin does not depend on this workspace package.

pnpm --filter @elaraai/east-plugin run build
pnpm --filter @elaraai/east-plugin run generate-index   # → index.json (commit it)
make -C libs/east-plugin package                        # both hosts' bundles + the assembled plugins under marketplace/

Index generation requires built examples and the Python environment, as documented in either host README. After runtime changes, build this package before bundling hosts. Codex build and Claude build do that automatically, and assemble their own plugin; a root recursive build follows the workspace dependency graph.

Edit the skill's owning library, or its native source here. Claude Code's plugin copies the catalog through its links at package time; Codex's materializes and adapts the same sources then. Nothing generated is committed under either host. Run both host test suites after changes to shared behavior: they run over the assembled plugins.

Publishing

The release publishes the assembled directories as they are — @elaraai/east-claude-plugin and @elaraai/east-codex-plugin on the lockstep version, with scripts/publish-plugins.mjs — and the public catalog elaraai/plugins lists each as an npm source pinned at its released version, for both hosts. A new package name is bootstrapped once by hand (scripts/bootstrap-plugins-npm.mjs) before trusted publishing can be configured for it.

Building on East's plugin

A plugin for a product built on East — its own skills and its own examples — runs the same machinery over its own corpus, each piece called with the plugin's own names: the index generator, the example search and its MCP tools, the search-first hooks and the Codex skill adapter. East's own plugins are these, called with East's names.

npm install @elaraai/east-plugin@<the East packages' version>

Versions. @elaraai/east-plugin ships on the one version every @elaraai/* package shares, and depends on @elaraai/east and @elaraai/east-diagnostics at that version. Pin it exactly to the version of the East packages your examples use, and move them together. The East index it ships is that version's corpus.

The index

An index.config.json names the packages whose *.examples.ts(x) are indexed, as East's index.config.json does: a source with ir: true is a package whose examples are East programs, read from its built test modules (dist) and stored as IR with the TypeScript printed from it; any other is stored as its authored source. Hand-written entries (a CLI's, say) go in an index.static.json of { "entries": [...] }.

npx east-plugin-generate-index --base-dir . --config index.config.json --static index.static.json --out index.json
# the python printings of the programs, optional (without them a program answers in TypeScript only):
uv run --with elaraai-east-py python node_modules/@elaraai/east-plugin/scripts/render-python.py index.json

From code, generateIndex({ baseDir, config, staticEntries }) (@elaraai/east-plugin/scripts/generate-index) returns the index to write.

The search

The search and fetch tools register on any MCP server with registerExampleTools(server, { index, searchTool, getTool, corpus, packages, scopes }), which answers once the index has loaded: a server awaits it before it connects, so an index that does not load fails it at startup, naming why. scopes are the npm scopes the corpus's packages are installed under, @elaraai unless given: the package filter accepts a name under any of them, and the search tool tells the agent not to read the installed packages there. A plugin composes its corpus with East's one of two ways:

  • One server answering both corpora. Serve East's index beside your own: the package filter knows both, and an example id names its package, so the two never collide.

    import { fileURLToPath } from "node:url";
    import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
    import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
    import { registerExampleTools } from "@elaraai/east-plugin/mcp/example-tools";
    import { EAST_INDEX_PATH } from "@elaraai/east-plugin/lib/east-index";
    
    const server = new McpServer({ name: "acme", version: "1.0.0" });
    await registerExampleTools(server, {
      index: [EAST_INDEX_PATH, fileURLToPath(new URL("../index.json", import.meta.url))],
      searchTool: "search_acme_examples",
      getTool: "get_acme_example",
      corpus: "Acme",
      packages: ["acme-cloud", "east", "e3"],
    });
    await server.connect(new StdioServerTransport());
  • One each. The East plugin, installed beside yours, answers East's corpus with its own tools; your server serves your index alone.

EAST_INDEX_PATH names the installed package's index.json. A bundled server, as East's plugins bundle theirs, copies that file into the plugin at build time and reads it from there.

The package

A plugin a host installs is one directory with every file real and nothing depended on. assemblePlugin (@elaraai/east-plugin/lib/package) writes it from your plugin's source — its manifest directory, its esbuild .build/, and each of hooks/hooks.json, .mcp.json, .lsp.json, README, LICENSE and (Claude Code) commands/ and agents/ it has — your skills catalog (symlinks followed, a linked skill directory's included; adapted in your names for Codex), and your index, with a generated package.json that has no dependency. It is staged beside out and moved into place once complete, so a failure leaves an earlier assembly as it was; an out holding anything but an earlier assembly, or overlapping the source, is refused:

import { assemblePlugin } from "@elaraai/east-plugin/lib/package";

await assemblePlugin({ host: "claude", source: "packages/acme-claude-plugin", skills: "packages/acme-plugin/skills", index: "packages/acme-plugin/index.json", out: "marketplace/acme-claude-plugin" });
await assemblePlugin({ host: "codex", source: "packages/acme-codex-plugin", skills: "packages/acme-plugin/skills", index: "packages/acme-plugin/index.json", out: "marketplace/acme-codex-plugin", names: ACME });

Publish each directory with npm publish <dir> --access public on your release, and list the packages in the elaraai/plugins catalog, which pins each at its released version for both hosts. The same directories, beside a .claude-plugin/marketplace.json and .agents/plugins/marketplace.json with relative sources, are a local marketplace for development, as East's scripts/package.ts writes one.

The hooks

Claude Code runs a hook per event. Each is the shared function, configured with your names:

// hooks/pre-write.ts — the gate on a write of your code with no search on record
import { gateText, type SearchGuidance } from "@elaraai/east-plugin/lib/search-guidance";
import { runPreWriteGate } from "@elaraai/east-plugin/lib/search-hooks";
import { SEARCH_TOOLS } from "@elaraai/east-plugin/lib/transcript";

const ACME: SearchGuidance = {
  searchTool: "mcp__plugin_acme_acme__search_acme_examples",
  getTool: "mcp__plugin_acme_acme__get_acme_example",
  corpus: "Acme",
  scope: "@elaraai",
};
await runPreWriteGate({
  searchTools: [ACME.searchTool, ACME.getTool, ...SEARCH_TOOLS], // a search of East's corpus counts too
  gateText: gateText(ACME),
  isCorpusCode: (code) => /@elaraai\/acme/.test(code),
  markerPrefix: "acme-search-seen",
  requireSearchEnv: "ACME_REQUIRE_SEARCH",
});

The read reminder is runPreReadReminder({ readText: readText(ACME), isCorpusRead: corpusReadFor(ACME.scope) }). Codex runs one hook over every tool: codexSearchGate(event, options) (lib/codex-hook.ts) records a search by your tools after the call, and before it reminds a read of your corpus and gates a write of your code; writeSearchHookReply writes its answer.

Skills

A plugin ships its own skills; East's come from the East plugin installed beside it. Codex caches only the plugin itself, so a Codex plugin ships its skills as real files, adapted from the Claude Code ones: materializeSkills(sources, target, names) (lib/codex-skills.ts) adapts each skill's Markdown — your tools lose Claude Code's MCP prefix, /acme: becomes $acme-codex-plugin:, the words speak of Codex — and copies every other file.