CLI-Anything:CLI 扩展框架与工具集
CLI 扩展框架,包含技能注册、AdGuardHome 管理和 TypeScript 扩展,支持多语言 CLI 工具开发。
CLI-Anything:多语言 CLI 扩展框架
项目背景
CLI-Anything 的灵感来源于 VSCode 的插件生态——如果命令行工具也能像 VSCode 一样通过插件机制动态扩展功能,那就太好了。我日常需要在终端中完成大量操作(查看 DNS 状态、管理服务、运行脚本),每个操作对应一个独立的 CLI 工具,使用起来很零碎。CLI-Anything 的目标是提供一个统一框架:通过一个命令行入口管理所有工具,插件可插拔,支持多种语言开发。
这个项目也是我在 U3W-AI 实习期间接触 MCP Server 架构后对 CLI 工具标准化的一次实践探索。
架构设计
cli-anything/
├── cli.py # 主入口,负责插件发现和命令路由
├── plugins/ # 插件目录
│ ├── dns/ # AdGuardHome DNS 管理插件
│ ├── skills/ # 技能注册插件
│ └── system/ # 系统管理插件
├── plugin_api.py # 插件接口规范
核心机制是插件发现:启动时扫描 plugins/ 目录,自动注册每个子目录中的 plugin.py(Python 插件)或 plugin.ts/plugin.js(TypeScript 插件)。每个插件只需实现一个约定的接口:
class PluginInterface:
@property
def name(self): ...
@property
def description(self): ...
def register_commands(self, cli_group): ...
框架负责:命令路由、参数解析、输出格式化。插件只关心自己的业务逻辑。
多语言支持
这是 CLI-Anything 和其他 CLI 框架最大的区别。大多数 CLI 框架(如 Click、argparse、Commander.js)只支持单一语言。CLI-Anything 通过子进程调用实现跨语言:
- Python 插件:直接 import 加载
- TypeScript 插件:通过
ts-node或编译后的 JS 执行 - 未来可扩展:Go、Rust 等语言的编译产物
实际插件:AdGuardHome DNS 管理
实际在用的是一个 DNS 管理插件,通过 AdGuardHome REST API 实现:
# 查询当前 DNS 拦截统计
cli-anything dns stats
# 添加自定义拦截规则
cli-anything dns block --domain ads.example.com
# 查看最近查询记录
cli-anything dns query --limit 20
这个插件在日常运维中很实用——不用打开浏览器登录 AdGuardHome 后台,终端里一条命令搞定。
踩坑记录
1. 插件热加载与可靠性
设计的初衷是"插件随便写、框架自动发现",但实际中发现:插件出错(语法错误、未捕获异常)会导致整个 CLI 崩溃。解决:插件加载使用 importlib 的异常隔离,每个插件在独立沙箱中验证后再注册。
2. 跨语言通信的数据格式
TypeScript 插件输出给 Python 框架需要约定数据格式。最终统一用 JSON 通过 stdout 传递,框架读取子进程的 stdout 解析结果。错误信息走 stderr。
3. Windows 兼容性
我在 Windows 上开发,但部分插件(如系统管理)需要 Linux 特有的命令。解决方案:插件声明 platform 字段,框架自动过滤不兼容当前系统的插件。
与 MCP 的关系
CLI-Anything 和 MCP Server 在思路上有异曲同工之处:都是一种工具标准化框架。MCP 是 AI 客户端与工具的接口标准,CLI-Anything 是终端用户与工具的接口标准。两者可以互为补充——MCP Server 包装的 AI 工具可以在 CLI-Anything 中注册为命令,反之亦然。