Skip to content

OpenTray v0.21.1:改进创建体验,全新安装可用

jixoai v0.21.1 opentray

给命令行工具、AI skill 与本地守护进程一个常驻托盘入口,不必引入 Electron。向导的命令录入按生态选择、表单化,换 runner 应用身份不变,env 注入显式可见;全新安装 404 已修复。

$ npm view create-opentray version
0.21.1

OpenTray v0.21.1 发布了(2026-09-06,仓库的第一份 GitHub Release)。OpenTray 给命令行工具、AI skill 和本地守护进程这类轻量程序一个常驻的托盘入口:有图标、有菜单、能收点击事件,不必为一个小图标引入 Electron。这一篇把 0.21.0 与 0.21.1 合并成一篇来讲,变更集中在创建工具 create-opentray;两个 release 的完整清单在文末链接逐个列出。

现有命令,一行包装成托盘应用

已经在本地起 HTTP 服务的命令,npx create-opentray 直接把它包装成 OpenTray 应用。三条进入路径都在 create-app 指南里:

npx create-opentray web      # 浏览器向导,交互式
npx create-opentray create --app-id com.example.build \
  --app-name "Build" --exec "npm run dev"   # 完全非交互
npx create-opentray skill    # 内置 AI skill,交给代理读

命令录入按生态选择

向导里的命令输入收敛成单行输入组(command families):一个生态选择前缀,加命令体。选中 npm / Go / Rust / Python / .NET 之一,命令体从自由文本变成结构化表单;确认后写回命令串,取消则整个输入作废。自由输入的自定义命令保持原样。

细节:生态清单与表单字段

五个生态家族覆盖的 runner 是 npm 系的 npx, pnpx, bunx, yarn dlx, nubx, deno run, vpx,另有 go run, cargo install, uvx/pipx run 与 dnx。表单字段为 runner、包标识(包名 / 模块 / crate / 工具 id)、版本与参数;Rust 系列额外填要运行的二进制名,并显示安装参考行。

细节:表单会话、cargo 守卫与参数保真

打开表单即冻结取消快照,未确认的编辑只存在于会话内;取消(按钮 / X / 遮罩 / ESC)整体丢弃,切换生态再切回不丢草稿。

cargo install 永不被向导执行:解析后的可执行文件归一为 cargo 且参数含独立 install token 时直接拒绝,并指引改用 Rust 表单。判定刻意保守,宁可误拒罕见的带 install 参数的其它 cargo 子命令。

参数按 POSIX 对称引号重新序列化,tokenize(build(parse(cmd))) 逐项一致;webui 镜像与 core 用同一版本 shell-quote。带值的 runner 选项(如 deno run --config <path>)原样回落自定义,不把选项值当包名。

换 runner,应用身份不变

appId 从生态推导,不跟着 runner 走:同一个包在 npm 系里换 runner(npx 换 bunx)拿到同一个 appId,应用身份不漂移。

npx @deepseek-ai/dsh@latest web   → web.dsh.npmjs
go run rsc.io/fortune@latest      → fortune.golang
cargo install ripgrep(rg)        → rg.rust
细节:appId 推导规则

识别出的生态家族取「选项前子命令段 + 归一化包名」,缀上生态尾(npmjs / golang / rust / python / dotnet)。Rust 取运行二进制名,Python 的 . 与 _ 归一为 -,@scope, @version, npm: 前缀与路径尾巴都剥掉。自定义命令沿用既有推导,不受影响。

env 注入显式可见

跳过 npx / pnpx 首次安装确认的 npm_config_yes=true 过去由向导隐式注入,现在改为用户 env 清单里的显式条目,清单是唯一来源。向导里的预设开关是条目的双向投影,开启即写入,移除即删除;在清单外手工改动会即时回灌,重复键最后一个生效。命令行上的指示图标在条目存在时点亮。

写代码的应用,一个 createTray() 起步

不走创建工具、直接写代码的应用,不需要打包器,也不加载 Node addon,一个 createTray() 起步:

import { createTray, type TrayIcon } from "opentray";

let tray;
tray = await createTray(
  {
    id: "com.example.first-app",
    icon: { "text-only": "OT" },
    menu: {
      items: [
        { title: "Quit", primaryEvent: true, onMenuClick: () => void tray.destroy() },
      ],
    },
  },
  { appId: "com.example.first-app", appName: "First App" },
);

应用代码经公共 tray/session 协议与运行时对话。协议本体四个:App 是调用方持有的运行时身份与隔离边界;Tray 是一个 app 下的单个托盘图标及其状态;Session 是托盘事件与变更的实时权威来源;Extension 是只作用于该 app 与其托盘的原生能力包。更早的 Space / Surface 一代已从公共 API 退役。

细节:工作区与发布拓扑

工作区所有包按固定版本一起发布。

  • opentray(SDK + CLI)

  • @opentray/spec(协议契约)

  • @opentray/packaging

  • 四个 bundler 适配器:@opentray/vite-plugin, tsdown-plugin, esbuild-plugin, webpack-plugin(同一 manifest 形状)

  • @opentray/ext-webview 与各平台 WebView 动态库

  • @opentray/ext-badge

  • @opentray/<os>-<arch> 平台运行件

ext-island 是路线图项,尚未发布;Lynx 扩展独立维护在 jixoai/opentray-ext-lynx。

其余变更

  • 修复全新安装 404(0b0fe63):私有 workspace 包 @create-opentray/core 与 @create-opentray/cli 误入运行时 dependencies,npm 解析不到直接 404;移入 devDependencies 后由 tsdown 打进单一发布产物,无残留 import。

  • 0.21.0 全新安装必失败,0.21.1 是 command families 第一个装得上的版本。

  • 发布自动化上线(9e68724c):每个发布版本自动切一份 GitHub Release,tag 即包版本,notes 是 changesets 生成的 changelog 节。本版走 bootstrap 路径补切,是仓库的第一份;下一版起全自动。本站的版本 pill 也从「v—」第一次显示出版本号。

  • 同线发布:@opentray/spec、@opentray/packaging、@opentray/vite-plugin 等随本版一起发 0.21.1,完整清单见「写代码的应用」节的折叠。

从 0.20.0 的版本提交之后到本版版本提交(含),共 22 个提交:严格 conventional 前缀计 feat 2, fix 8, docs 6, test 2, chore 3,另 1 个是 changeset 提交。破坏性口径:带 ! 标记的提交 0 个,无迁移动作。

升级

npm i create-opentray@0.21.1   # 0.21.0 全新安装 404,直接装 0.21.1
npm i opentray@0.21.1          # SDK 同线

使用官方扩展时锁同一条协议线:pnpm add opentray@stable-A-B @opentray/ext-webview@stable-A-B(协议线 tag 由 @opentray/spec 发布,勿与 latest 混用)。

致谢

感谢 2026-08-20 报告安装失败的那次反馈,devDependencies 的判定规则由此收紧。

链接