70b1145b5e
* refactor: remove version field from GenerateOutcome and EarlyHint All consumers are in the same repo and evolve together — version field adds ceremony without practical value at this stage. Keeps schema_version in VerifiedArtifactMetadata (sidecar file format). * refactor: migrate all 123 CLI adapters from YAML to TypeScript Remove YAML as an adapter format entirely. All adapters now use TypeScript with cli() from @jackwener/opencli/registry. - Convert 123 YAML adapter files to TypeScript via batch script - Remove YAML scanning from discovery.ts (registerYamlCli, yaml import) - Remove scanYaml() and shouldReplaceManifestEntry() from build-manifest.ts - Change synthesize.ts to output JSON candidates (internal format) - Change generate-verified.ts to write .ts adapter files instead of .yaml - Delete yaml-schema.ts (dead code) and scripts/yaml-to-ts.mjs (one-time tool) - Update all tests to match new format Closes discussion in #OpenCLI thread 47ddba82. * fix: close YAML migration gaps in plugin scaffold, validation, and scan - plugin-scaffold.ts: generate hello.ts (TS pipeline) instead of hello.yaml - plugin.ts validatePluginStructure: no longer accept .yaml as valid command file - plugin.ts scanPluginCommands: remove .yaml/.yml from scanned extensions - discovery.ts: add explicit log.warn() when YAML files detected in clis/ or plugins/ - plugin.test.ts: update all test fixtures from .yaml to .js - plugin-scaffold.test.ts: update hello.yaml references to hello.ts - Delete dead src/yaml-schema.ts Resolves PR #887 review blockers from @mbp-codex-pr0. * refactor: complete YAML removal across docs, skills, record, and binance adapters Code changes: - record.ts: candidate output changed from .yaml (yaml.dump) to .json (JSON.stringify), removed js-yaml import - src/clis/binance: convert all 11 YAML adapters to TypeScript cli() format - binance/commands.test.ts: rewrite to use registry instead of yaml.load - skill-generate.test.ts, diagnostic.test.ts: update mock paths from .yaml to .ts - build-manifest.ts, synthesize.ts: update stale YAML comments Documentation: - README.md: remove .yaml from Dynamic Loader, fix plugin types, fix synthesize comment - README.zh-CN.md: fix synthesize comment - CONTRIBUTING.md: replace YAML Adapter section with Pipeline Adapter (TS), update arg examples - docs/developer/yaml-adapter.md: replaced with deprecation redirect - docs/developer/architecture.md: remove YAML pipeline references - docs/developer/contributing.md: remove YAML adapter section - docs/developer/ai-workflow.md: YAML → TS in synthesize description - docs/guide/getting-started.md: remove .yaml from loader, update engine description - docs/guide/plugins.md: remove YAML plugin option, update plugin types - docs/index.md, docs/comparison.md: remove YAML adapter references - docs/zh/guide/plugins.md: remove .yaml from scan description Skills: - opencli-explorer/SKILL.md: rewrite YAML vs TS decision tree to TS-only - opencli-oneshot/SKILL.md: replace YAML templates with TS cli() templates - opencli-generate/SKILL.md: YAML artifact path → TS artifact path - opencli-usage/SKILL.md, plugins.md: update adapter format references * fix: clean up remaining YAML adapter references in docs - docs/zh/guide/plugins.md: replace YAML plugin example with TS pipeline - docs/developer/testing.md: YAML Adapter heading → Adapter, remove validate line - TESTING.md: same fix in root testing doc - CONTRIBUTING.md: remove "YAML validation" comment - docs/.vitepress/config.mts: mark YAML Adapter Guide as (Deprecated) in nav - docs/advanced/download.md: remove "YAML Adapters" from pipeline step heading
225 lines
6.7 KiB
Markdown
225 lines
6.7 KiB
Markdown
# Plugins
|
|
|
|
OpenCLI supports community-contributed plugins. Install third-party adapters from GitHub, and they're automatically discovered alongside built-in commands.
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
# Install a plugin
|
|
opencli plugin install github:ByteYue/opencli-plugin-github-trending
|
|
|
|
# List installed plugins
|
|
opencli plugin list
|
|
|
|
# Update one plugin
|
|
opencli plugin update github-trending
|
|
|
|
# Update all installed plugins
|
|
opencli plugin update --all
|
|
|
|
# Use the plugin (it's just a regular command)
|
|
opencli github-trending repos --limit 10
|
|
|
|
# Remove a plugin
|
|
opencli plugin uninstall github-trending
|
|
```
|
|
|
|
## How Plugins Work
|
|
|
|
Plugins live in `~/.opencli/plugins/<name>/`. Each subdirectory is scanned at startup for `.ts` or `.js` command files — the same formats used by built-in adapters.
|
|
|
|
### Supported Source Formats
|
|
|
|
```bash
|
|
# GitHub shorthand
|
|
opencli plugin install github:user/repo
|
|
opencli plugin install github:user/repo/subplugin # install specific sub-plugin from monorepo
|
|
opencli plugin install https://github.com/user/repo
|
|
|
|
# Any git-cloneable URL
|
|
opencli plugin install https://gitlab.example.com/team/repo.git
|
|
opencli plugin install ssh://git@gitlab.example.com/team/repo.git
|
|
opencli plugin install git@gitlab.example.com:team/repo.git
|
|
|
|
# Local plugin (for development)
|
|
opencli plugin install file:///path/to/plugin
|
|
opencli plugin install /path/to/plugin
|
|
```
|
|
|
|
The repo name prefix `opencli-plugin-` is automatically stripped for the local directory name. For example, `opencli-plugin-hot-digest` becomes `hot-digest`.
|
|
|
|
## Plugin Manifest (`opencli-plugin.json`)
|
|
|
|
Plugins can include an `opencli-plugin.json` manifest file at the repo root to declare metadata:
|
|
|
|
```json
|
|
{
|
|
"name": "my-plugin",
|
|
"version": "1.0.0",
|
|
"opencli": ">=1.0.0",
|
|
"description": "My awesome plugin"
|
|
}
|
|
```
|
|
|
|
| Field | Description |
|
|
|-------|-------------|
|
|
| `name` | Plugin name (overrides repo-derived name) |
|
|
| `version` | Semantic version |
|
|
| `opencli` | Required opencli version range (e.g. `>=1.0.0`, `^1.2.0`) |
|
|
| `description` | Human-readable description |
|
|
| `plugins` | Monorepo sub-plugin declarations (see below) |
|
|
|
|
The manifest is optional — plugins without one continue to work exactly as before.
|
|
|
|
## Monorepo Plugins
|
|
|
|
A single repository can contain multiple plugins by declaring a `plugins` field in `opencli-plugin.json`:
|
|
|
|
```json
|
|
{
|
|
"version": "1.0.0",
|
|
"opencli": ">=1.0.0",
|
|
"description": "My plugin collection",
|
|
"plugins": {
|
|
"polymarket": {
|
|
"path": "packages/polymarket",
|
|
"description": "Prediction market analysis",
|
|
"version": "1.2.0"
|
|
},
|
|
"defi": {
|
|
"path": "packages/defi",
|
|
"description": "DeFi protocol data",
|
|
"version": "0.8.0",
|
|
"opencli": ">=1.2.0"
|
|
},
|
|
"experimental": {
|
|
"path": "packages/experimental",
|
|
"disabled": true
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Installing
|
|
|
|
```bash
|
|
# Install ALL enabled sub-plugins from a monorepo
|
|
opencli plugin install github:user/opencli-plugins
|
|
|
|
# Install a SPECIFIC sub-plugin
|
|
opencli plugin install github:user/opencli-plugins/polymarket
|
|
```
|
|
|
|
### How It Works
|
|
|
|
- The monorepo is cloned once to `~/.opencli/monorepos/<repo>/`
|
|
- Each sub-plugin gets a symlink in `~/.opencli/plugins/<name>/` pointing to its subdirectory
|
|
- Command discovery works transparently — symlinks are scanned just like regular directories
|
|
- Disabled sub-plugins (with `"disabled": true`) are skipped during install
|
|
- Sub-plugins can specify their own `opencli` compatibility range
|
|
|
|
### Updating
|
|
|
|
Updating any sub-plugin from a monorepo pulls the entire repo and refreshes all sub-plugins:
|
|
|
|
```bash
|
|
opencli plugin update polymarket # updates the monorepo, refreshes all
|
|
```
|
|
|
|
### Uninstalling
|
|
|
|
```bash
|
|
opencli plugin uninstall polymarket # removes just this sub-plugin's symlink
|
|
```
|
|
|
|
When the last sub-plugin from a monorepo is uninstalled, the monorepo clone is automatically cleaned up.
|
|
|
|
## Version Tracking
|
|
|
|
OpenCLI records installed plugin versions in `~/.opencli/plugins.lock.json`. Each entry stores the plugin source, current git commit hash, install time, and last update time. `opencli plugin list` shows the short commit hash when version metadata is available.
|
|
|
|
## Creating a Plugin
|
|
|
|
### Creating a TypeScript Plugin
|
|
|
|
```
|
|
my-plugin/
|
|
├── package.json
|
|
├── my-command.ts
|
|
└── README.md
|
|
```
|
|
|
|
`package.json`:
|
|
|
|
```json
|
|
{
|
|
"name": "opencli-plugin-my-plugin",
|
|
"version": "0.1.0",
|
|
"type": "module",
|
|
"peerDependencies": {
|
|
"@jackwener/opencli": ">=1.0.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
`my-command.ts`:
|
|
|
|
```typescript
|
|
import { cli, Strategy } from '@jackwener/opencli/registry';
|
|
|
|
cli({
|
|
site: 'my-plugin',
|
|
name: 'my-command',
|
|
description: 'My custom command',
|
|
strategy: Strategy.PUBLIC,
|
|
browser: false,
|
|
args: [
|
|
{ name: 'limit', type: 'int', default: 10, help: 'Number of items' },
|
|
],
|
|
columns: ['title', 'score'],
|
|
func: async (_page, kwargs) => {
|
|
const res = await fetch('https://api.example.com/data');
|
|
const data = await res.json();
|
|
return data.items.slice(0, kwargs.limit).map((item: any, i: number) => ({
|
|
title: item.title,
|
|
score: item.score,
|
|
}));
|
|
},
|
|
});
|
|
```
|
|
|
|
### TS Plugin Install Lifecycle
|
|
|
|
When you run `opencli plugin install`, TS plugins are automatically set up:
|
|
|
|
1. **Clone** — `git clone --depth 1` from GitHub
|
|
2. **npm install** — Resolves regular dependencies
|
|
3. **Host symlink** — Links the running `@jackwener/opencli` into the plugin's `node_modules/` so `import from '@jackwener/opencli/registry'` always resolves against the host
|
|
4. **Transpile** — Compiles `.ts` → `.js` via `esbuild` (production `node` cannot load `.ts` directly)
|
|
|
|
On startup, if both `my-command.ts` and `my-command.js` exist, the `.js` version is loaded to avoid duplicate registration.
|
|
|
|
## Example Plugins
|
|
|
|
| Repo | Type | Description |
|
|
|------|------|-------------|
|
|
| [opencli-plugin-github-trending](https://github.com/ByteYue/opencli-plugin-github-trending) | TS | GitHub Trending repositories |
|
|
| [opencli-plugin-hot-digest](https://github.com/ByteYue/opencli-plugin-hot-digest) | TS | Multi-platform trending aggregator (zhihu, weibo, bilibili, v2ex, stackoverflow, reddit, linux-do) |
|
|
| [opencli-plugin-juejin](https://github.com/Astro-Han/opencli-plugin-juejin) | TS | 稀土掘金 (Juejin) hot articles, categories, and article feed |
|
|
| [opencli-plugin-rubysec](https://github.com/nullptrKey/opencli-plugin-rubysec) | TS | RubySec advisory archive and advisory article reader |
|
|
|
|
## Troubleshooting
|
|
|
|
### Command not found after install
|
|
|
|
Restart opencli (or open a new terminal) — plugins are discovered at startup.
|
|
|
|
### TS plugin import errors
|
|
|
|
If you see `Cannot find module '@jackwener/opencli/registry'`, the host symlink may be broken. Reinstall the plugin:
|
|
|
|
```bash
|
|
opencli plugin uninstall my-plugin
|
|
opencli plugin install github:user/opencli-plugin-my-plugin
|
|
```
|