插件进岛屿有两条路:只在自己的电脑上用,或者放进插件市场,让别人在 设置 → 插件市场 里安装。
许可证
插件用什么许可证由你定,开源闭源都可以。岛屿本体是 GPL-3.0,但插件是单独运行的程序,只通过 JSON-RPC 和岛屿通信,不受 GPL 约束。SDK、脚手架、PowerShell 模块和示例插件都是 MIT,拿来写插件不会给你的插件带来任何许可要求。
插件市场目前要求源码公开,以便审核。
只在自己的电脑上用
把插件文件夹放进 %APPDATA%\com.tixxin.fuyu\plugins\<插件 id>\,在 设置 → 插件扩展 打开「允许运行第三方插件」,点 重新加载,再启用插件。不经过市场,也不需要签名。改了文件再点一次 重新加载。
想给朋友用:npx fuyu-plugin pack 打出 zip 发给他,让他照上面解压到插件目录。
放进插件市场
市场列表来自 TixXin/fuyu-plugins 仓库。插件包放在你自己仓库的 GitHub Release 里,市场仓库只记录插件在哪里;它的 CI 每小时检查一次新版本,校验后重建索引并签名。完整步骤见那里的 CONTRIBUTING.md。
第一次上架
npx fuyu-plugin validate检查,npx fuyu-plugin pack打包,得到<id>-<version>.zip。建议同时签名,见下文的「作者签名」。- 在自己的仓库发布 GitHub Release:标签是清单的
version(可以带v),附件是这个 zip(签了名的再加上.zip.sig),文件名不能改。脚手架生成的 GitHub Actions 工作流在你推送版本标签时会自动做这一步。 - 向
fuyu-plugins开 pull request,只新增一个文件plugins/<插件 id>.json(见下文)。PR 会自动检查所有权、下载并校验插件包;维护者阅读源码后合并,一小时内插件出现在插件市场。
npx fuyu-plugin publish(加 --sign 同时签名)会打包,并打印这些步骤。
以后的版本
提高清单的 version,在自己的仓库发新的 Release 就行,一小时内市场会更新。以下版本不会自动上架,要等维护者审核:申请了新权限、第一次加入自定义网页、换了运行时(例如 .ps1 换成 .js)。
已发布的版本不能修改:用户安装时核对的就是那个哈希值,同一个版本号的包变了,市场 CI 会拒绝。有问题就发新版本号。
市场里的描述文件
fuyu-plugins 里的 plugins/<插件 id>.json:
{
"id": "com.example.clock",
"repo": "example/fuyu-clock",
"publisher": "example",
"categories": ["productivity", "developer"]
}
| 字段 | 说明 |
|---|---|
id |
插件 id,和清单相同 |
repo |
owner/name,必须公开;插件详情里的「仓库」按钮打开它 |
publisher |
repo 的所有者(GitHub 用户或组织),市场上显示为发布者。你必须是它本人,或该组织的公开成员 |
categories |
只能取 productivity、todos、developer、media、messages、information、utilities;音效包写 sounds |
path |
可选,插件在仓库里的文件夹,例如 plugins/clock,默认仓库根目录 |
tagPrefix |
可选,一个仓库放多个插件时的标签前缀,例如 clock-(标签 clock-v1.2.0) |
preRelease |
可选,true 时也收录标成 Pre-release 的 Release,见下文 |
signingKeys |
可选,你的签名公钥,见下文的「作者签名」 |
domain |
可选,用来成为已验证发布者的域名,见下文 |
说明和版本历史
插件的 README.md 和 CHANGELOG.md 会写进市场索引(各最多 16 KB),显示在插件市场的详情里,也显示在官网的插件页上。先在插件包里找;包里没有(写进了 .fuyuignore)时,读仓库里 Release 标签处 path 文件夹中的同名文件。它们跟着版本走,改了要发新版本才会更新。
- 支持标题、段落、列表、引用、代码块、粗体、斜体和 http(s) 链接;HTML 和图片不显示(图片只显示替代文字)。
CHANGELOG.md建议每个版本一节、最新的在最前(## 1.2.0)。
预发布版本
描述文件里写 "preRelease": true 时,标成 Pre-release 的 Release 也会收录,版本号用 semver 预发布后缀(例如 1.3.0-beta.1)。
- 插件市场只列正式版。
- 用户在插件设置页打开「接收这个插件的预发布版本」后,更新会安装比正式版新的预发布版本。
- 正式版发布后(例如
1.3.0高于1.3.0-beta.2),装着预发布版本的用户会更新到正式版。关掉开关不会退回旧版本。
作者签名
签名是可选的,但签了名,用户的岛屿才会自动更新你的插件。岛屿还会记下第一次看到的密钥,之后换了密钥的版本要用户确认才装。这样即使你的 GitHub 账号或仓库被盗,攻击者发的新版本也不会悄悄装到用户电脑上。
- 只需一次:
npx fuyu-plugin keygen生成签名密钥。私钥存在~/.fuyu-plugin/signing.key(Windows 上用 DPAPI 加密,只有当前 Windows 账户能解开),也可以用环境变量FUYU_PLUGIN_SIGNING_KEY(PEM 文本)提供。它打印的{ keyId, publicKey }写进描述文件的"signingKeys": [ … ]。 - 每次发版:
npx fuyu-plugin pack --sign,把<id>-<version>.zip和<id>-<version>.zip.sig一起附到 Release。已经打好的包可以用npx fuyu-plugin sign <zip>补签。 - 登记了
signingKeys之后,没有签名或签名不对的版本不会上架,维护者也不能放行。
备份私钥。 丢了只能换新密钥,而换密钥后的第一个版本要每个用户手动确认。最安全的做法是在自己电脑上签名再上传,不要把私钥放进仓库的 CI。
换密钥
旧密钥还在时,在插件文件夹里运行 npx fuyu-plugin keys rotate(一把密钥签多个插件时加 --ids a,b):
- 它把旧密钥改名为
<密钥文件>.<旧 keyId>.old留着,在原位置生成新密钥,并打印每个插件要加进signingKeys的新条目。新条目里的endorsedBy是旧密钥对「插件 id + 新密钥」的签名。 - 把新条目加在旧密钥后面(旧密钥先别删),开 PR。
- 合并后用新密钥签名发版。岛屿看到新密钥有已记下的密钥的证明,就当作同一个作者,照常自动更新。
丢了旧密钥就做不出证明,换密钥后的第一个版本要用户手动确认。
用户那边会看到什么
- 安装:第一次安装某个发布者的插件时,按钮显示 信任并安装。装好后插件默认是关闭的,用户到 设置 → 插件扩展 里启用并授权。
- 标签:签了名的插件带「作者已签名」;带自定义网页的带「自定义界面」;按
runtime标出「无需另外安装」或「需要 Node.js」;可选权限标成「可选,用到时询问」。 - 更新:岛屿在启动 30 秒后和之后每 6 小时检查一次市场,有新版本时卡片上提示。「自动更新插件」打开时,只有作者签了名(密钥和已安装的版本相同)、来自可信发布者、而且不申请新权限的更新会自动安装,其他的只提示。
- 点赞:插件上架后,
fuyu-plugins会在它的 Discussions 里自动开一条点赞帖,每小时统计帖子的 👍,市场卡片显示这个数字。想让用户来点赞,把帖子地址放进 README。
安装链接
fuyu://market/install/<插件 id> 打开岛屿的 设置 → 插件市场,并把这个插件置顶。官网插件页的「在浮屿中安装」按钮用的就是它,你也可以放进自己的 README。
链接本身不会安装任何东西:用户在置顶的卡片上自己点「安装」,照常经过信任发布者和权限的确认。插件不在市场里时会提示链接无效。需要浮屿 0.3.6 或更新的版本,旧版会忽略这种链接。
已验证发布者
市场在发布者名字旁显示「已验证 · GitHub 组织」或「已验证 · <域名>」,说明发布者确实是它的名字所指的组织或个人,不代表插件安全。
- 在 GitHub 上验证过域名的组织自动得到。
- 其他发布者在描述文件里写
"domain": "example.com",并让https://example.com/.well-known/focusd-publisher.json返回{ "github": "<publisher>" }。市场每小时重新检查一次。
下架
发现某个版本有严重问题(比如会删数据),到 fuyu-plugins 开 issue 或 PR 申请撤销。被撤销的版本:
- 已安装的会被停用(或按申请卸载,插件数据保留),插件卡片显示原因;
- 不能再启用,也不能从市场安装;
- 手动放进插件目录的同 id 同版本也会被拦截。
撤销不能取消,误撤销的插件请发一个新版本。撤销名单的格式和签名见 插件市场运维。
安装时岛屿检查什么
- 市场索引的签名有效。
- 下载的包大小和 SHA-256 与索引一致。
- zip 里的路径没有跳出插件目录,解压后总大小不超过 100 MB。
- 清单的
id和version与索引一致,申请的权限没有超出索引里列出的。 - 有作者签名时签名有效;签名密钥和已安装的版本不同时,要用户确认。
全部通过才替换旧版本。更新时保留启用状态,但新版本要更多权限时插件会暂停,等用户重新授权。卸载插件会删除插件目录和授权记录,但保留 plugins-data/<id>/ 里的数据和凭据管理器里的秘密。