跳转到内容

cnb-rs extensions

cnb-rs 的 extension 系统让你用任何语言(Rust / Go / bash / Python ...)写出第三方子命令,安装后就能像内置命令一样调用。

当前状态(Phase 3.1):dispatch 骨架已 ship — 手工放 binary 到 extensions 目录即可工作。 install / upgrade / remove / list 子命令在 Phase 3.2+ 实现, 完整设计文档见仓库 .windsurf/docs/cnb-extension-design.md

工作原理

$ cnb-rs hello world

   ├─[1] clap 解析顶层 args;"hello" 不在内置命令集
   ├─[2] fallback:clap external_subcommand ["hello", "world"] cnb-rs main
   ├─[3] cnb-rs 查找 $EXTENSIONS_DIR/cnb-hello/cnb-hello[.exe]
       ├─ 找到 Command::spawn(bin).args(["world"]).status()
       └─ 找不到 报错 + 提示 'cnb-rs ext install cnb-hello'
   └─[4] 子进程退出码透传,stdin / stdout / stderr 不缓冲

安装位置

平台extensions 根目录
Linux$XDG_DATA_HOME/cnb/extensions~/.local/share/cnb/extensions
macOS~/Library/Application Support/cnb/extensions
Windows%LOCALAPPDATA%\cnb\extensions

可通过环境变量 CNB_EXTENSIONS_DIR 覆盖(绝对路径;测试 / dev 场景常用)。

命名约定

  • 仓库名 / extension 命令名必须以 cnb- 开头:例如 cnb-stats / cnb-prom-export / cnb-todo

  • 用户调用时不带 cnb- 前缀:cnb-rs stats 实际查找 cnb-stats/cnb-stats[.exe]

  • 单 extension 布局:

    extensions/
    └── cnb-stats/
        ├── cnb-stats[.exe]    # Unix 无后缀,Windows 自动 `.exe`
        ├── manifest.toml      # Phase 3.4 起 install 自动写
        └── ...                # extension 自带资源

extension 子进程的环境

cnb-rs 在 dispatch 时向 extension 子进程注入以下环境变量:

变量含义
CNB_BIN当前 cnb-rs 可执行文件的绝对路径,方便 extension 反向调用 $CNB_BIN api /...(避免 PATH 中找错版本)
CNB_EXTENSION_NAME当前 extension 命令名(不含 cnb- 前缀,如 stats
CNB_DOMAIN解析后的目标 CNB 域名(默认 cnb.cool
CNB_REPO解析后的仓库路径(解析失败时不设置,避免误传空值)

Token 不主动注入:让 extension 通过 $CNB_BIN api ... 间接使用 token,或继承父进程已有的 CNB_TOKEN 环境变量(与 gh extension 行为一致)。

手工安装 extension(Phase 3.1 临时方案)

在 Phase 3.4 的 cnb-rs ext install 子命令 ship 之前,可以手工放 binary:

bash
# 1. 拿到 binary(自己 build 或下载 release)
$ cargo build --release --bin my-extension
$ cp target/release/my-extension cnb-hello

# 2. 放到 extensions 目录
$ mkdir -p ~/.local/share/cnb/extensions/cnb-hello
$ mv cnb-hello ~/.local/share/cnb/extensions/cnb-hello/

# 3. 调用(cnb-rs 会自动 dispatch)
$ cnb-rs hello world

Windows 类似(路径换为 %LOCALAPPDATA%\cnb\extensions\cnb-hello\cnb-hello.exe)。

用 5 行 bash 写个 extension

bash
#!/usr/bin/env bash
# extensions/cnb-whoami/cnb-whoami
set -e
"$CNB_BIN" api /user --jq .username

赋可执行权限后 cnb-rs whoami 即输出当前登录用户名。

Phase 3.1–3.4 仅支持 binary extension(直接可执行的文件,含编译产物或 shebang script)。完整的 interpreted script extension(含 kind = "script" 标记 + 跨平台 shell 启动)在 Phase 5 实现。

Phase 3.4 之后,install 会在每个 extension 目录里落地 manifest.toml,记录 host / owner / repo / tag / kind / sha256 等元数据,供 list / upgrade 使用。手工放的旧 binary 没有 manifest 也能 list / exec / remove,仅 version / repo 显示为 -(向前兼容)。

state.toml 与 24h 后台 check

Phase 3.6 引入全局 state 文件 $EXTENSIONS_DIR/state.toml(不在某个 extension 目录内),记录:

  • [updates]:上次全量 check 的时间戳 + 待提示的「有新版本」消息列表
  • [extensions.cnb-<name>]:每个 extension 最近一次 check 拉到的 latest release tag

两者职责严格分离:manifest 是安装凭证(不可变),state 是运行时缓存(可变)。

触发时机

两类调用会在前台进程内同步走 gate(< 5ms)后 spawn detached 子进程 在后台跑实际的 N × API check(Phase 6 Task C 把原 sync in-process 换成 detach):

  • cnb-rs ext list 调用时
  • 任意 extension dispatch 路径(cnb-rs <ext-name> ...,如 cnb-rs stats)启动时

子进程跑的是 hidden subcommand cnb-rs ext _check-upgrades(不出现在 --help),把新版本消息加进 state.updates.pending_notices 队列。前台 cnb-rs 不再 block。

其它 cnb-rs 命令(如 auth login / repo list不会触发 check,零额外开销。

详细 detach 机制(Windows CREATE_NO_WINDOW | DETACHED_PROCESS / Unix process_group(0) / parent 抢先 pre-write state 防 retry storm)见 cnb-rs ext upgrade 文档

提示打印

任何 cnb-rs 命令 main entry 早期调 print_pending_notices(),读 state 把队列输出到 stderr 后清空并写回:

$ cnb-rs auth status
💡 cnb-stats 有新版本可用(v0.1.0 v0.1.1),运行 'cnb-rs ext upgrade stats' 升级
(设 CNB_NO_EXTENSION_NOTICE=1 禁用此提示)
 已登录 user@cnb.cool

禁用

设以下任一环境变量即可永久禁用 check 和提示:

  • CNB_NO_EXTENSION_NOTICE=1:明确禁用 extension 提示
  • CI=true:CI 平台通用约定(GitHub Actions / GitLab / CNB Pipeline 等默认设)

state IO 失败(磁盘满 / permission / TOML corrupt)在打印路径上被 silently 吞掉,不会令 cnb-rs 主命令失败。

命名冲突

extension 不能覆盖任何内置命令(如 auth / issue / pr 等)。如果你试图安装一个与内置命令同名的 extension:

内置命令名清单从 clap Cli::command().get_subcommands() 动态获取,避免维护双份。

Roadmap

Phase内容状态
3.1dispatch 骨架 + extensions 目录约定 + env var 注入 + 内置 helper(list_installed / builtin_commands_from✅ 已 ship
3.2cnb-rs ext list 子命令(alias ls✅ 已 ship
3.3cnb-rs ext exec 显式 dispatch(避命名冲突)✅ 已 ship
3.4manifest.toml + cnb-rs ext install + SHA256 校验 + 冲突检测 + list 表格升级✅ 已 ship
3.5cnb-rs ext remove(alias rm / uninstall✅ 已 ship
3.6cnb-rs ext upgrade + 24h 后台 check(Phase 6 Task C 改 detached subprocess)+ state.toml + CNB_NO_EXTENSION_NOTICE✅ 已 ship
43 个官方 extension 仓库孵化(cnb-chat / cnb-stats / cnb-stars)✅ 已 ship
5registry + cnb-rs ext search + cnb-rs ext create 脚手架 + interpreted script + Local kind + ext registry validate✅ 已 ship
6Task A --web + min_cnb_rs_version / Task B ext registry refresh + daily CI / Task C detached upgrade check / Task D ext browse TUI✅ 已 ship

完整设计与时间线见仓库 .windsurf/docs/cnb-extension-design.md

参见

  • cnb-rs ext — extension 管理子命令总入口
  • cnb-rs api — extension 反向调用 CNB OpenAPI 的「生态基石」命令
  • cnb-rs completion — shell 补全脚本生成(extension 命令名暂不在补全列表,Phase 3.4 后改进)

Released under the MIT License.