Skip to content

feat: Support plugin system in opencli#191

Open
ByteYue wants to merge 6 commits intojackwener:mainfrom
ByteYue:support_plugin
Open

feat: Support plugin system in opencli#191
ByteYue wants to merge 6 commits intojackwener:mainfrom
ByteYue:support_plugin

Conversation

@ByteYue
Copy link
Collaborator

@ByteYue ByteYue commented Mar 21, 2026

Description

Add a plugin system to opencli, enabling community-contributed adapters.

Users can now install third-party plugins from GitHub repos, and the plugins are automatically discovered at startup alongside built-in commands.

This PR implements the first 3 stages of the plugin roadmap:

  • Stage 0: Core plugin directory scanning (~/.opencli/plugins/)
  • Stage 1: Two demo plugin repos as reference implementations
  • Stage 2: opencli plugin install/uninstall/list command group

Also fixes a pre-existing CDPBridge bug discovered during testing.

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 🌐 New site adapter
  • 📝 Documentation
  • ♻️ Refactor
  • 🔧 CI / build / tooling

Checklist

  • I ran the checks relevant to this PR
  • I updated tests or docs if needed
  • I included output or screenshots when useful

What's New

Plugin Management Commands

opencli plugin install <source>    # Install from GitHub
opencli plugin list                # List installed plugins
opencli plugin uninstall <name>    # Remove a plugin

Plugin Layout Convention

YAML plugin (zero-dependency, no build step):

opencli-plugin-github-trending/
├── repos.yaml
└── README.md

TS plugin (with peerDep):

opencli-plugin-hot-digest/
├── package.json     # peerDependencies: { "@jackwener/opencli": ">=1.0.0" }
├── aggregate.ts     # import { cli, Strategy } from '@jackwener/opencli/registry'
└── README.md

Demo Plugin Repos

Repo Type Description
opencli-plugin-github-trending YAML Browse GitHub Trending repositories
opencli-plugin-hot-digest TS Cross-platform trending aggregator

TS Plugin Lifecycle

TS plugins are automatically handled during opencli plugin install:

  1. Clonegit clone --depth 1 from GitHub
  2. Depsnpm install --production for regular dependencies
  3. Link — Symlinks host @jackwener/opencli into plugin's node_modules/ (ensures import from '@jackwener/opencli/registry' resolves against the running host, not a stale npm-published version)
  4. Transpile — Uses the host's esbuild to compile .ts.js (production node cannot load .ts directly)
  5. Discover — On next startup, .js files are preferred over .ts siblings to avoid duplicate registration

Screenshots / Output

Install

$ opencli plugin install github:ByteYue/opencli-plugin-github-trending

✅ Plugin "github-trending" installed successfully.
   Restart opencli to use the new commands.

List

$ opencli plugin list

  Installed plugins

  github-trending (repos) ← https://github.com/ByteYue/opencli-plugin-github-trending.git

  1 plugin(s) installed

Plugin automatically appears in opencli list:

$ opencli list | grep github-trending

  github-trending
    repos [cookie] — GitHub Trending repositories

Plugin Execution — Table Output

$ opencli github-trending repos --limit 10

  github-trending/repos
┌──────┬───────────────────────────────────────────┬────────────┬───────┬──────────────────────────────────────────────────────────────────┐
│ Rank │ Name                                      │ Language   │ Stars │ Description                                                      │
├──────┼───────────────────────────────────────────┼────────────┼───────┼──────────────────────────────────────────────────────────────────┤
│ 1    │ jarrodwatts/claude-hud                    │ JavaScript │ 0     │ A Claude Code plugin that shows what's happening ...             │
├──────┼───────────────────────────────────────────┼────────────┼───────┼──────────────────────────────────────────────────────────────────┤
│ 2    │ langchain-ai/open-swe                     │ Python     │ 0     │ An Open-Source Asynchronous Coding Agent                         │
├──────┼───────────────────────────────────────────┼────────────┼───────┼──────────────────────────────────────────────────────────────────┤
│ 3    │ obra/superpowers                          │ Shell      │ 0     │ An agentic skills framework & software dev methodology ...      │
├──────┼───────────────────────────────────────────┼────────────┼───────┼──────────────────────────────────────────────────────────────────┤
│ 4    │ opendataloader-project/opendataloader-pdf │ Java       │ 0     │ PDF Parser for AI-ready data. Open-source.                       │
├──────┼───────────────────────────────────────────┼────────────┼───────┼──────────────────────────────────────────────────────────────────┤
│ 5    │ louis-e/arnis                             │ Rust       │ 0     │ Generate any location from the real world in Minecraft           │
├──────┼───────────────────────────────────────────┼────────────┼───────┼──────────────────────────────────────────────────────────────────┤
│ 6    │ newton-physics/newton                     │ Python     │ 0     │ GPU-accelerated physics simulation engine built upon NVIDIA Warp │
├──────┼───────────────────────────────────────────┼────────────┼───────┼──────────────────────────────────────────────────────────────────┤
│ 7    │ vas3k/TaxHacker                           │ TypeScript │ 0     │ Self-hosted AI accounting app. LLM analyzer for receipts ...     │
├──────┼───────────────────────────────────────────┼────────────┼───────┼──────────────────────────────────────────────────────────────────┤
│ 8    │ TauricResearch/TradingAgents              │ Python     │ 0     │ TradingAgents: Multi-Agents LLM Financial Trading Framework      │
├──────┼───────────────────────────────────────────┼────────────┼───────┼──────────────────────────────────────────────────────────────────┤
│ 9    │ openrocket/openrocket                     │ Java       │ 0     │ Model-rocketry aerodynamics and trajectory simulation software   │
└──────┴───────────────────────────────────────────┴────────────┴───────┴──────────────────────────────────────────────────────────────────┘
9 items · 5.7s · github-trending/repos

Plugin Execution — JSON Output

$ opencli github-trending repos --limit 3 -f json

[
  {
    "rank": 1,
    "name": "jarrodwatts/claude-hud",
    "description": "A Claude Code plugin that shows what's happening - context usage, active tools, running agents, and todo progress",
    "language": "JavaScript",
    "stars": "0",
    "url": "https://github.com/jarrodwatts/claude-hud"
  },
  {
    "rank": 2,
    "name": "langchain-ai/open-swe",
    "description": "An Open-Source Asynchronous Coding Agent",
    "language": "Python",
    "stars": "0",
    "url": "https://github.com/langchain-ai/open-swe"
  },
  {
    "rank": 3,
    "name": "obra/superpowers",
    "description": "An agentic skills framework & software development methodology that works.",
    "language": "Shell",
    "stars": "0",
    "url": "https://github.com/obra/superpowers"
  }
]

Hot-Digest Plugin — Multi-Source Aggregate

$ opencli hot-digest aggregate --sources v2ex,stackoverflow,bilibili,zhihu,weibo --limit 3

  hot-digest/aggregate
┌──────┬───────────────┬──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬─────────────┐
│ Rank │ Source        │ Title                                                                                                                        │ Heat        │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 1    │ v2ex          │ 请问下各位佬都在用什么 terminal 工具的                                                                                       │ 112         │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 2    │ v2ex          │ 看到中转造假的文章,作为中转系统 New API 作者真的很心寒                                                                      │ 98          │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 3    │ v2ex          │ AI 真的改变好多了,站里再也没人讨论微服务、分库分表、事务一致性了。。。。                                                    │ 57          │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 4    │ stackoverflow │ How to write a SqlAlchemy query to get a list of keys from a JSON column, but return it as a single list, not separate rows? │ 0           │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 5    │ stackoverflow │ Polymarket Relayer v2 — POST /submit returns 400 "bad request" with Gnosis Safe + Privy custodial wallet                     │ 0           │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 6    │ stackoverflow │ Are Enviornment Variables Still Considered a Secure Choice for Production?                                                   │ 0           │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 7    │ bilibili      │ 卡片上铭刻着我们的灵魂!【水无月菌】                                                                                         │ 1114720     │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 8    │ bilibili      │ 安禄山因何而死?香积寺究竟是不是冷兵器对决的巅峰?《安史之乱09》                                                             │ 284227      │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 9    │ bilibili      │ 走过路过,不要错过!我们的品质,普普通通,我们的价格,没有极限,欢迎来到——富人直播间!(纯属虚构,如有冒犯,先道歉🙇🏻‍♀️         │ 2780986     │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 10   │ zhihu         │ 人贩子「梅姨」落网,对贩卖儿童事实供认不讳,已被依法逮捕,她将面临哪些法律制裁?                                             │ 1842 万热度 │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 11   │ zhihu         │ 游客在壶口瀑布外拍视频称「门口要钱一人一百」被景区投诉,具体是什么情况?这算侵犯名誉权吗?                                   │ 807 万热度  │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 12   │ zhihu         │ 新疆沙漠全部铺上太阳能发电板,新疆的生态环境会发生什么变化?                                                                 │ 435 万热度  │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 13   │ weibo         │ 梅姨被逮捕                                                                                                                   │ 8120797     │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 14   │ weibo         │ 谢某某就是梅姨                                                                                                               │ 2263885     │
├──────┼───────────────┼──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼─────────────┤
│ 15   │ weibo         │ 清明小长假火车购票日历                                                                                                       │ 1376290     │
└──────┴───────────────┴──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴─────────────┘
15 items · 15.4s · hot-digest/aggregate

Uninstall

$ opencli plugin uninstall github-trending

✅ Plugin "github-trending" uninstalled.

Changes

File Description
src/discovery.ts discoverPlugins() scans ~/.opencli/plugins/; prefers .js over .ts sibling
src/main.ts Calls discoverPlugins() after built-in discovery
src/plugin.ts [NEW] Plugin management: install, uninstall, list, host symlink, TS transpile
src/registry-api.ts [NEW] Public API entry point for TS plugin peerDependencies
src/plugin.test.ts [NEW] 9 unit tests for plugin management
src/cli.ts Register opencli plugin install/uninstall/list commands
src/engine.test.ts +2 discoverPlugins unit tests
package.json exports field for ./registry (TS plugin peerDep support)
src/registry.ts globalThis shared registry for cross-module-instance safety
src/browser/cdp.ts Bugfix: CDPBridge timeout treated seconds as milliseconds
docs/guide/plugins.md [NEW] Plugin system user guide

Test Results

17/17 tests pass
tsc --noEmit — clean, no type errors

ByteYue added 2 commits March 21, 2026 11:58
- Stage 0: discoverPlugins() scans ~/.opencli/plugins/ at startup
- Stage 1: demo plugin repos (github-trending, hot-digest)
- Stage 2: opencli plugin install/uninstall/list commands
- package.json exports ./registry for TS plugin peerDep support
- 17 new/updated tests, tsc --noEmit clean
opts.timeout is passed in seconds from runtime.ts but CDPBridge
was using it as milliseconds, causing instant timeout (30ms).
@ByteYue ByteYue requested a review from jackwener March 21, 2026 04:31
ByteYue added 2 commits March 21, 2026 13:53
- Add src/registry-api.ts: re-exports core registration API (cli, Strategy,
  getRegistry) without transitive side-effects, safe for plugin imports
- Update package.json exports: './registry' -> './dist/registry-api.js'
- Update src/registry.ts: use globalThis shared registry to ensure single
  instance across npm-linked plugin modules
- Update .gitignore for plugin-related artifacts
After npm install, replace the npm-installed @jackwener/opencli
with a symlink to the running host's package root. This ensures
TS plugins always resolve '@jackwener/opencli/registry' against
the host installation, avoiding version mismatches when the
published npm package lags behind.
@Astro-Han
Copy link
Contributor

Nice! Plugin system is a natural next step for opencli — and the execution here is solid:

  • YAML plugins with zero dependencies make it really easy for the community to contribute
  • github:user/repo convention + prefix stripping feels clean
  • Demo repos as reference implementations are a great touch

One heads-up: this PR builds on discovery.ts, but main currently has the discovery logic in engine.ts — will need a rebase or a prior refactor to land cleanly.

Exciting to see this taking shape!

ByteYue added 2 commits March 21, 2026 14:06
…very

- installPlugin: after symlinking host opencli, transpile any .ts files
  to .js using esbuild from the host's node_modules/.bin/
- discoverPluginDir: skip .ts files when a .js sibling exists (production
  node cannot load .ts directly)
- scanPluginCommands: deduplicate basenames via Set to avoid showing
  'aggregate, aggregate' when both .ts and .js exist
- New docs/guide/plugins.md covering:
  - Installation/uninstallation commands
  - Creating YAML plugins (zero-dep)
  - Creating TS plugins (with peerDep)
  - TS plugin install lifecycle (clone → deps → symlink → transpile)
  - Example plugins and troubleshooting
- Add Plugins to VitePress sidebar (EN + ZH)
- Link from getting-started.md Next Steps
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants