@elaraai/east-plugin

中文文档
1.0.107发布于 2026/11/13AGPL-3.0-or-laterES Module构建来源已验证近 30 天下载 3366

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.

原始使用文档
文档目录7 节
  1. Publishing
  2. Building on East's plugin
  3. The index
  4. The search
  5. The package
  6. The hooks
  7. Skills

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 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.

版本与发布记录

@elaraai/east-plugin 共发布 23 个版本,首次发布于 2026/10/07;过去 12 个月发布了 23 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.0.107latest2026/11/13今天
1.0.1062026/11/094 天前
1.0.1052026/11/085 天前
1.0.1042026/11/067 天前
1.0.1032026/11/049 天前
1.0.1022026/11/0310 天前

关于 @elaraai/east-plugin 的常见问题

@elaraai/east-plugin 是什么?

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.

如何安装 @elaraai/east-plugin?

在项目目录运行 npm install @elaraai/east-plugin,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:typescript(>=5.0.0 <7)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。它还提供命令行工具 east-plugin-generate-index,可以用 npx east-plugin-generate-index 直接运行。

@elaraai/east-plugin 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/elaraai__east-plugin 是否存在。

@elaraai/east-plugin 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@elaraai/east-plugin 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@elaraai/east-plugin 可以商用吗?

@elaraai/east-plugin 使用 AGPL-3.0-or-later 许可。最严格的 Copyleft:除分发外,通过网络向用户提供基于它的服务也需要开源对应源码。闭源 SaaS 使用前务必评估。以上为概括,不构成法律意见,请以许可原文为准。

@elaraai/east-plugin 的下载量有多少?

根据 npm 官方下载统计,@elaraai/east-plugin 在 2026/10/13 – 2026/11/11 这 30 天内被下载 3,366 次,日均约 112 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@elaraai/east-plugin 还在维护吗?

最新版本 1.0.107 发布于 2026/11/13(今天);至今共发布 23 个版本,其中过去 12 个月发布了 23 个;首次发布于 2026/10/07。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。