插件目录与安装
这一页说明插件怎样从 GitHub 或 ZIP 装进 Covel:玩家看到的流程、能粘贴哪些链接、安装和更新的 HTTP 接口,以及各项限制。给玩家的分步说明见安装插件与世界包,给作者的发布说明见发布。部署、排查安装问题或对接安装接口时读这一页。
官方目录是 covel-ai/covel-plugins。目录里每个插件是一个 JSON 条目,README 的表格由这些条目生成。第三方插件的源码留在作者自己的仓库;官方扩展和示例可以放在目录仓库的独立子目录里。
分类与信任
- 内置插件随 Covel 一起安装。官方扩展和社区插件按需安装。
- 维护者标签和功能分类只用于展示,不参与权限判定。
- 根清单的
kind: core | plugin说明插件的角色。source: builtin | community由插件被发现的目录决定。 - 从外部安装的官方插件也属于
community,不自动启用。代码审批由发现位置与实例的可信来源策略共同决定,满足下述条件时可免提示。
WARNING
插件的服务端 JavaScript 没有运行在进程沙箱里。公共 API 的权限检查限制不了任意第三方 JavaScript 对进程文件、环境变量和网络的访问。被目录收录、通过源码摘要比对、通过静态清单检查,都不等于做过安全审计。
可信来源
默认没有可信来源,官方仓库也不例外。在 设置 → 安装与管理 → 可信来源 添加 GitHub 所有者或 owner/repo。建议按钮只填入官方仓库,必须再按“添加”才保存。条目会去掉两端空白、转为小写、去重并排序;最多 100 条,每条最多 100 个字符,所有者最多 39 个字符。只接受 GitHub 名称,不接受 URL。
owner 匹配该所有者的全部仓库;owner/repo 只匹配这个仓库。匹配不分大小写,按完整名称比较,owner-evil、repo-evil 不会匹配;非 GitHub HTTPS 地址、.git 后缀、末尾斜杠、额外路径、查询和片段都不匹配。合集的每个插件按它自己的安装记录 source.repository 判断,包括固定到其他仓库的成员。
个人形态(桌面和自部署 Web)的实例所有者通过现有 PUT /api/config/server-settings 保存 trust.sources;桌面壳设置了令牌时仍要带上它。托管与 browser-private 形态只使用运营者的 COVEL_TRUSTED_SOURCES(逗号分隔),忽略数据库里的值。环境变量覆盖存储值,界面显示锁定,写入回答 409 server_setting_fixed;共享形态的写入回答 403 server_settings_operator_only。变量有一条不合法就整体视为未设置,并在启动日志报告。修改环境变量需要重启;个人形态修改存储值立即生效,其他服务端进程通过设置缓存刷新跟上。
能力快照
GitHub 插件预览始终包含 capabilities 和 trustedSource。确认安装可信来源的插件时,.covel-install.json 增加可选的 capabilities,内容就是预览过的能力:
serverCode:是否含服务端代码或模块引用。http:根清单及每个 runtime 声明的来源与方法并集,省略方法表示GET。hooks:事件与enforce(默认normal)的组合。tools:贡献的工具名与 runtime 的tools.builtin。actions、services(契约 ID;写服务记成<契约> (write))、wires、extensions(<point>/<id>)、forms。datasets:contributes.datasets的命名空间与允许的写操作,不是安装用的合集。
所有列表排序去重。当前能力必须是快照的子集:HTTP 方法、数据集写操作也要逐项包含,钩子换阶段算新增能力,服务改成写服务(access: write)也算:它能改调用方回合里提供者自己的数据,所以要重新确认。给模型用(modelFacing)不进快照。更新可信来源的插件时,原快照原样带到新记录;原记录没有快照就仍然没有。因此更新不能默默扩大批准范围。非可信来源不写入新快照,世界包不写快照。
文件验证与自动授权
启动时对每个已登记、带路径的社区包验证安装记录与内容摘要,不 import 代码。启用、执行预检和延迟加载服务端代码之前再次检查;路径、大小、修改时间等 stat 签名未变时复用摘要结果。
integrity | 含义与处理 |
|---|---|
verified | 文件摘要与记录一致;还要检查当前来源策略与能力快照。 |
modified | 文件改动、新增、删除,或有链接、特殊文件;列表显示警告,使用普通审批。 |
no-receipt | 没有安装记录,例如 ZIP 导入或手工复制;不警告,使用普通审批。 |
unreadable | 记录损坏、带未知字段或其他读取失败;记录日志并显示警告,使用普通审批。 |
只有社区包现在的来源受信任、摘要为 verified、有能力快照且当前能力没有超出快照,才隐式授予 covel:plugin-server-code 和该包的 runtime:*。缺少任一条件、登记后还未重新验证或读取异常,都回到普通提示。移除来源立即停止隐式授权;已有的显式会话授权仍按原规则生效。共享宿主的 operator 检查仍先执行,来源策略不会替代它。
普通的服务端代码审批被允许后,仅对可信且摘要匹配的社区包原子更新快照为当前能力;写失败只记日志,不撤销审批。这个改写使更早签发的更新预览失效:确认更新回答 409 Installed package changed; check for updates again,需要重新检查更新。旧安装记录没有快照时,第一次符合上述条件的普通批准会记录一份;记录仅增加可选字段,不需要重建数据。
恢复已有活动会话时,第一次回合的延迟 entry 发布也走同一激活入口;发布重新登记插件后再次验证,保持随后的 runtime 快照授权有效,无须额外启用请求。
开发热重载重新登记包时,验证结果立即失效。改过本地文件的包变成 modified,失去来源隐式授权,直到普通审批通过;只要摘要仍不符,该审批也不会更新快照。撤销会话授权只清除显式授权,不能按会话撤销实例的来源策略。
可信来源不改变 builtin | community 分类,不添加 API 或权限,也不自动选中插件。ZIP、手工目录、世界包、逐操作的 RPC 授权和载荷绑定的一次性授权不在此机制内。快照是声明的上界,不是沙箱或代码审计;GitHub 账号失窃不在保护范围内。发布签名、密钥、回滚、过期与撤销元数据尚未实现;预览 token 的宿主签名只是确认本次安装内容。
用户流程
打开 设置 → 安装与管理:
- 浏览社区目录,或粘贴公开的 GitHub 仓库链接、
/tree/<ref>/<path>链接。 - 解析链接。这个目录下的插件和世界包会一起列出。目录里有
covel-collection.yaml时,只列出合集清单指定的成员,包括固定在其他仓库的包。 - 勾选要安装的内容,核对 ID、版本、来源、commit 和代码风险,确认一次后安装。先安装插件,再安装世界。失败时撤回本次写入;世界已被用于创建会话,或删除失败时会保留并报告,见批量安装的撤回结果。
- 装了插件需要重启后端一次,然后在会话中启用插件,并按审批流程允许它执行。世界立即可用。
桌面端菜单里的导入入口打开同一个包管理页面。ZIP 由服务端做静态检查,并展示检查结果。
预览里的完整性检查
预览同时给出完整性检查的结果。检查只读清单,不执行插件代码。
| 情况 | 级别 | 结果 |
|---|---|---|
插件根 requires 或世界 pluginPolicy.requires 的契约,在“已安装 + 本次所选”的插件里没有提供者 | 错误 | 涉及的包被勾选时不能安装 |
| 宿主版本不在包声明的范围内 | 错误 | 涉及的包被勾选时不能安装 |
| 世界请求的插件不存在 | 警告 | 可以安装 |
| 契约有多个提供者,而世界没有指定用哪个 | 警告 | 可以安装 |
| 扫描目录时有读不出的包(清单无效、身份冲突等) | 警告 | 这个包被跳过,其余的仍可安装 |
| 合集清单点名的成员读不出 | 错误 | 整次预览失败 |
语言
语言不是安装条件。 插件至少有 English。没有玩家语言的文字时照常安装和启用,标签回退到 English(或翻译目录里的译文)。
- 重启后,插件列表的
languages字段给出它有文字和有指令的语言。 - 会话准备页给没有当前界面语言文字的插件标上“未翻译”。
- 作者在发布前运行
pnpm validate:plugin <dir>,可以看到同一份摘要。
装到哪里,谁能装
- 安装写入当前连接的后端,不一定是浏览器所在的机器。桌面实例写入本机;远程部署写入服务器。
- 安装、预览、查询安装记录和卸载共用安装 API 的权限门控。demo / commercial 部署必须使用运营者令牌。生产环境的自托管实例需要桌面令牌,或者设置
COVEL_INSTALL_API_ENABLED=1。
重启、重载和覆盖
- 本地 ZIP 导入一直可用,界面要求先确认代码风险。
- GitHub 安装记录和磁盘目录独立于启动时的 registry。所以新安装的、加载失败的和等待卸载的插件,在重启之前仍然可以管理。
- 安装和卸载都需要重启。
- 卸载先把整个插件目录移到
.covel-uninstall-*,再删除文件。改名失败时保留完整的原目录并报错;改名后的清理失败只记日志,下次启动重试,不会加载残缺的包。 - 已加载的社区插件在开发模式下支持单插件热重载。
- 没有后台自动更新。
- 普通安装不覆盖同 ID 的目录。更新走单独的确认流程,见检查与更新。
GitHub 输入与发布物
能粘贴哪些链接
- 仓库根链接、指向 tag / commit / branch 的 tree 链接,以及插件子目录的链接。
- 普通的仓库链接通过 GitHub API 解析默认分支当前的 commit。tree 链接解析指定的 ref。
- ref 里含
/时,在 URL 对应的那一段写成%2F,或者改用 commit SHA。 - 仓库转移后产生了重定向时,需要粘贴新的规范地址。
一个仓库里有多个插件
框架在所选目录里递归寻找插件包(例如 plugins/ 和 examples/),忽略隐藏目录和 node_modules。
| 粘贴的链接 | 列出什么 |
|---|---|
https://github.com/covel-ai/covel-plugins | 全部可安装的包 |
https://github.com/covel-ai/covel-plugins/tree/main/plugins | 只有功能插件 |
继续指定到 plugins/mimo-tts | 直接预览这一个插件 |
- 所选目录本身就是一个插件包时,按一个完整的包处理,它的
runtimes/不会被拆开安装。 - 一次最多预览 20 个插件。超出时请指定更具体的目录。
设置页显示每个插件的 ID 和它在仓库里的路径。勾选、审阅风险后确认安装。
- 每次安装都重新下载同一个固定 commit 的归档,但只提取所选包的目录,不复制其他插件或仓库根目录的工具。
- 预览过期后需要重新预览。
- 需要的插件全部装完之后,可以统一重启一次后端。
网络和来源
- GitHub API 解析和归档下载都走现有的 outbound 网络层,实时遵循设置里的直连、系统代理、HTTP(S) 或 SOCKS5 配置。没有另一套代理设置。
- 明确指定的 HTTP / SOCKS 代理失败时会报错,不会悄悄改成直连。
- 系统代理按系统解析出的路由顺序工作,包括系统明确返回的 DIRECT。
- 只下载公开的 GitHub 源码归档,不使用用户的 GitHub 凭证。
- 不自动下载 Release 附件,不接受任意 URL、私有仓库或 GitHub Enterprise。已构建的 Release ZIP 可以手动下载后导入。
包的布局要求
安装使用与加载器相同的清单与 runtime 目录规则,缺少 RUNTIME.md 的子目录会得到具体路径诊断。
- 插件包目录必须有根
PLUGIN.md。package.json可以没有;有的话必须声明"type": "module",否则返回 400。安装器不读它的version,版本只来自PLUGIN.md。 - 根声明使用
{ description, contributes, runtime? },加上需要时的id、version等字段。 - 多 runtime 的包把执行声明放在
runtimes/<sub>/RUNTIME.md。子声明使用{ schedule, io, agent/function },不重复插件身份。 - 根
runtime和子目录 runtime 不能同时声明。 - 平铺的旧字段、缺少根声明,或者子目录里有
PLUGIN.md,都会被拒绝安装。桌面端从文件夹导入时同样拒绝。 - 插件目录里已经有这种布局的包时,启动只把它登记为这个包自己的加载错误(
status: error),其余插件照常加载。
字段见插件契约参考。
开发模式下,补齐缺失的根 PLUGIN.md,或者把子 runtime 的清单改成 RUNTIME.md 之后,可以通过单插件重载重新校验。这次扫描不沿用启动时的布局错误。还没有发布过活动能力的失败社区包只恢复静态声明;执行 entry、handler 和 guard 仍然要正常授权。
安装器做什么,不做什么
插件 ID 按下面的顺序取第一个合法的值,不能和内置插件的 ID 相同(不分大小写,冲突时返回 409):
PLUGIN.md写的id。写了但不合法时返回 400。- 包所在的文件夹名:ZIP 里唯一的顶层文件夹(忽略
__MACOSX/),GitHub 上所选的子文件夹,或者包就在仓库根目录时的仓库名。 package.json的name,去掉 scope 和一个plugin-前缀(@someone/plugin-notes→notes)。
三者都没有合法值时返回 400,要求在
PLUGIN.md写id。清单和语言变体只接受普通的 YAML frontmatter,拒绝可执行的语言标记。
安装器不执行脚本、包管理器、编译器或插件模块。
所有插件安装入口(GitHub、ZIP、离线合集)和更新都要求运行文件自包含:
package.json的dependencies、optionalDependencies、peerDependencies必须省略或为空。devDependencies不受这条限制。宿主给每个插件提供@covel/plugin-handlers-utils和zod,插件不用声明它们为运行依赖;内置插件也只在devDependencies里写它们。声明了运行时依赖时,安装器返回 400,指出非空的字段,不写入包。作者应把依赖打进发布文件,再删除这些声明或留空。
需要构建的插件,作者应该在独立的发布目录里提供已构建、自包含的文件。
安装前的输入检查:内联 runtime 和子 runtime 的两种输入 scope 都检查本地 accepts 文件,以及包内 producer 是否存在。
- 缺文件、JSON 不合法、包内 producer 不存在,或者
scope: committed同时写了select,返回 400,不写入插件包。 - 这项检查不加载 entry、guard 或 handler。
- 可选的外部契约还没有提供者时,不会因此拒绝这个包。
归档限制
GitHub 源码归档带的一层外目录会被去掉,再提取指定的插件目录。普通上传的 ZIP 仍然要求包文件在 ZIP 的顶层。
| 限制 | 值 |
|---|---|
| 压缩文件大小 | 20 MiB |
| 条目数 | 2000 |
| 解压后大小 | 200 MiB |
| 膨胀比 | 100 |
- 这些限制作用于整个 GitHub 归档。大型 monorepo 请使用精简的发布仓库,或者本地 ZIP。
- 合集预览和批量安装的所有归档共用 200 MiB 解压预算,包括清单所在的归档。相同仓库、相同 commit 的归档只计一次;超过预算返回 413,停止读取后续成员。离线合集 ZIP 使用同一个预算。
- 符号链接、逃出目录的路径、只有大小写不同的重复文件路径都会被拒绝。
HTTP 契约
请求和响应的 Zod schema 在 @covel/shared 的 plugin-install 导出里。
| 接口 | 请求 | 响应 |
|---|---|---|
POST /api/install/plugin/github/preview | { url } | { items: GithubPluginPreview[] } |
POST /api/install/plugin/github | { token, acceptRisk: true } | { ok: true, kind: "plugin", id, restartRequired: true },201 |
GET /api/install/plugins | 无 | { items: [{ id, version, source, pendingUpdate, integrity, trustedSource }] } |
POST /api/install/plugin | multipart file | ZIP 安装响应 |
POST /api/install/github/preview | { url } | { collection, items: GithubPackagePreview[], problems } |
POST /api/install/github/batch | { tokens, acceptRisk: true } | { ok: true, installed: [{ kind, id }], restartRequired },201 |
POST /api/install/collection | multipart file | 同 batch 响应,201 |
多包预览和批量安装
/github/preview的每个 item 在单包预览字段之外带kind: "plugin" | "world"。它的token和单包接口签发的相同,可以用于单包安装,也可以用于 batch。collection:目录里有清单时为{ id, name, version },否则为null。problems是{ level: "error" | "warning", message, packageId? }[]。- batch 接受 1–20 个 token。它先下载并逐个核对摘要和身份;全部通过,并且目标都不存在,才开始写入。
- 任何一个目标已经存在时返回 409,不做任何修改。写入阶段失败时,回滚本次已经写入的包。世界回滚走正常删除生命周期:持有世界锁、写删除标记,并保证记录删除失败时包文件可恢复。
- 如果世界在安装期间已有会话,回滚会保留世界及会话。删除失败的包也会保留供重试。错误响应的
details含rolledBack和retained两个{ kind, id }[]清单;error同时列出未撤回的包,避免把部分失败当成全部撤回。 /collection接受pnpm pack:collection生成的 ZIP(清单在顶层,包含全部成员)。它没有预览这一步,完整性检查的错误直接返回 400。
宿主版本范围
插件根清单可以声明 covel 版本范围(如 ">=0.0.45 <0.1.0")。
- 宿主版本不在范围内时,预览、安装、更新和 ZIP 导入都会拒绝这个包,并给出两个版本号。
- 已经在磁盘上的包按同一个范围检查。服务端启动或重载时,宿主版本不在范围内(手动拷入的包,或者安装之后宿主版本变了),这个包登记为加载失败并显示同一条信息,它的代码不会执行。换成适配的版本后恢复。
- 语法见合集指南。
预览里有什么
预览包含 ID、包版本(PLUGIN.md 的 version)、描述、作者名(author,清单没有声明时为 null)、代码存在提示、来源、签名 token 和 expiresAt。
- 来源为
{ repository, commit, path, digest, tracking };capabilities始终列出请求的能力,trustedSource标记预览时来源是否被信任。 tracking为{ kind: "default-branch" }、{ kind: "branch", ref }或{ kind: "pinned", ref }。仓库根链接跟踪默认分支;tree 链接先尝试解析为明确的分支;其余的 tag 和 commit 保持锁定。description返回I18nText,保留locales/<locale>.yaml(也支持.yml)为PLUGIN.md提供的描述翻译。客户端按界面语言调用resolveI18nText。hasServerCode使用加载器的模块路径枚举:entry(没写时是存在的server/index.js)、function handler(没写时是RUNTIME.md旁边存在的handler.js)、guard、世界投影 handler;也扫描代码文件(包括.mts、.cts)。ZIP 安装响应返回同一字段。这是保守提示,不是完整的代码审计;测试或构建源码也可能触发它。- 适配的宿主版本由作者在清单的
covel、目录和 README 里声明。安装器只验证清单格式和这个范围,不判断 runtime 是否真的兼容。
签名和下载
- 预览不写入插件目录。
- 签名覆盖源仓库、commit、子目录、文件摘要和预览信息。它 15 分钟内有效,进程重启后失效。
- 安装只使用签名里的内容:重新下载固定的 commit,然后比对文件内容的摘要。摘要按路径排序,包含文件名和长度,所以不依赖 GitHub ZIP 在字节上保持稳定。
- 摘要变了或者签名过期,返回 409,需要重新预览并确认。
- 下载只访问固定的 GitHub API 和 codeload 地址,拒绝重定向,不转发运营者或浏览器的凭证,限制流式读取的字节数,单个请求 30 秒超时。
落盘和安装记录
- 确认安装之后,才通过临时目录加 rename 的流程落盘,并附加
.covel-install.json,记录来源、版本和安装时间。 - 这个文件记录来源和可选的能力快照;是否免提示还取决于当前策略与文件验证。插件包不能自带这个文件,文件名的大小写变体也会被拒绝。
- 用 ZIP 或手工安装的插件没有来源记录,接口返回
source: null。 - 取消预览不会写入插件目录。确认安装之后没有“取消提交”的操作。
启动时,在应用更新和发现插件之前,清理用户插件目录里的 .covel-install-*、.covel-uninstall-*,以及 .covel-updates/ 下未完成的 .covel-install-*。按插件 ID 排队的更新和事务备份保留,继续走更新恢复流程。清理不跟随符号链接;文件仍被占用时记日志,下次启动重试。
错误码
| 状态码 | 情况 |
|---|---|
| 400 | 输入或清单无效 |
| 401 / 403 | 没有权限 |
| 404 | 仓库或 ref 不存在 |
| 409 | 过期、冲突或内容发生变化 |
| 413 | 超出大小限制 |
| 429 | GitHub 限流 |
| 502 | 上游响应失败 |
网络传输异常沿用安装错误的响应格式。
检查与更新
设置里每个已安装的插件都有“检查更新”。
- 检查由玩家主动触发。不定时轮询,不自动下载替换。
- 从分支安装的插件跟踪保存的分支;从仓库根安装的跟踪当前的默认分支;从 tag 或 commit 安装的保持锁定。
- 可以展开“选择其他版本”,粘贴同一个仓库、同一个插件目录的版本链接。不能借更新切换来源或插件身份。
- 带
/的 tag 需要%2F编码,例如/tree/mimo-tts%2Fv0.0.40/plugins/mimo-tts。 - 不自动列出已发布的版本。
| 接口 | 请求 | 响应 |
|---|---|---|
POST /api/install/plugin/github/update/preview | { id, url? } | { status: "current" }、{ status: "pinned" } 或 { status: "available", preview } |
POST /api/install/plugin/github/update | { token, acceptRisk: true } | { ok: true, kind: "plugin", id, restartRequired: true },201 |
DELETE /api/install/plugin/github/update/:id | 无 | { ok: true },取消尚未应用的更新 |
更新预览
更新预览沿用安装预览的字段,增加 previous: { version, source } 和文件列表 changes: { added, modified, removed }。
- 界面显示当前版本和目标版本、精确的 commit、包内的文件变化,以及 GitHub 上整个仓库的提交对比链接。
- 只有所选插件目录的内容摘要变了才提示更新。同仓库里其他插件或根 README 的提交不会造成误报。
- 版本号没有递增但内容变了,仍然提示。由使用者核对后确认。
确认更新
- 签名区分“安装”和“更新”两种用途,并绑定当前的安装记录、目标内容和 15 分钟的有效期。
- 确认时重新下载固定的 commit,核对内容摘要、身份、清单和内置 ID 限制,再核对一次本地的安装记录和文件内容。
- 下载和检查沿用现有的代理、公开 GitHub 地址约束和归档上限。
- 同一个插件的安装、暂存、取消和卸载操作互斥。重复提交一个已经待安装的更新返回 409。
暂存,下次启动时替换
确认之后,新包和替换计划原子地写入用户插件目录的 .covel-updates/<id>/。运行中的文件不被覆盖。
GET /api/install/plugins的pendingUpdate为{ version, source, error }或null。这时当前的version仍然是旧包的版本。- 暂存的更新可以取消。卸载插件也会清理它暂存的更新。
- 用 ZIP 或手工安装的包,以及缺少有效来源记录的包,不提供自动检查。
下次后端启动时,在发现社区插件和加载代码之前:
- 重新检查旧包、暂存包和摘要。
- 把旧包移入事务备份,再把新包放到位。
- 放置失败时恢复旧包,并在安装列表里显示错误。正常完成后删除事务备份。
启动被中断时,下次会根据备份和目标内容恢复或完成这次替换。无法确定状态时停止启动,保留文件供人工恢复。这个流程只处理文件替换的失败,不会自动回滚插件运行之后的逻辑错误或数据变更。
更新不动什么
- 设置、会话、plugin-data 和 MediaStore 不属于插件包。更新不删除也不修改这些持久化数据。数据格式是否兼容由插件作者负责。
- 包目录里任何本地文件的增删或修改,以及符号链接,都会阻止替换。请先备份并处理这些改动。
- 旧进程始终使用旧文件。新进程里的社区执行授权重新建立,所以确认更新不会继承旧进程的执行授权。
- 一个插件安装目录应该只由一个后端进程管理。
符号链接
发现阶段会跟随插件目录里指向目录的符号链接,方便开发者把本地的插件源码链接进用户插件目录。安装和更新则拒绝符号链接。链接的目标可以在插件目录之外,所以不要让运营者以外的人写入用户插件目录。
NOTE
开发期的安装记录必须带 tracking 字段。没有这个字段的旧记录不会被推断更新来源,也不迁移:先备份本地的源码改动,再卸载,并从明确的来源重新安装。单独存储的会话数据不随卸载删除。
维护范围
下面几个插件在官方社区仓库里,主仓不内置:Jev 推荐 Demo、DashScope / OpenAI 生图、MiMo TTS。它们的插件 ID、runtime ID 和设置键与内置时相同。
从内置这些插件的版本升级上来的话:
- 已有会话需要先从目录安装对应的插件,重启后端,并重新授权服务端代码。原来的内置信任不会自动继承。
- 已有的存档、插件数据、模型配置和媒体不会被主动删除,也不需要迁移数据库结构。
当前不提供:
- 网页市场。
- 后台自动升级。
- 插件的隔离执行。
- 按目录标签提升权限。
- 按合集整体更新或卸载。合集只在安装时起作用,装好的成员各自独立更新和卸载。
会话选择与执行授权
选中一个插件和允许它的代码运行是两件事。
SessionRecord.activePlugins保存玩家的选择,不代表社区代码已经有执行授权。- 创建会话时保留解析后的全部选择。创建阶段的代码执行和生命周期 hooks 只使用已授权的集合。
GET /api/sessions/:id/plugins的active表示当前有效的授权。approvalRequired: true表示已选择,但当前进程里缺少这个会话的授权。- 没有被选择的插件不会显示为待授权。
Web 上的授权提示
Web 在创建或恢复会话后,用一个提示请求这些插件的授权。
- 提示列出每个待授权插件的名称、ID、版本和简介。默认全部勾选,玩家可以取消其中几个再确认。
- 提示先于审批请求。确认之后才为勾选的插件逐个发起请求、批准并启用。每个插件仍然各有一条审批请求和一份授权。
- 没有勾选的插件,或者选择“暂不授权”时,不产生任何请求。
- 逐个处理的原因:启用一个插件会让服务端清除同一个会话里其他暂停插件的待审批请求。
- 在插件列表里单独启用某个插件时,使用单项确认。
- 每次访问、每个插件只自动提示一次。
- 拒绝后保留暂停提示,可以主动重试或禁用。离开页面时不会替其他会话批准。
- 批准沿用 enable → approval → enable 的流程。
授权不跨后端重启保存,尤其不能在更新代码之后沿用旧的授权。内置插件自动加载,不需要授权。
应用内校验
没有源码或 pnpm 的玩家可以在 设置 → 安装与管理 点击已安装包的“校验”,也可以选择插件或世界类型后拖入 ZIP。ZIP 校验不会安装包。API 还接受允许目录内的路径;界面暂不提供目录选择器。
ZIP 校验使用安装时的插件 ID 规则,不会用临时目录名替代 package.json.name 或包文件夹推导的 ID。无法确定有效 ID 时,报告省略 id,返回 identity-invalid 错误和 ok: false;清单解析错误仍由静态校验器单独报告。
校验只读清单和引用的文件,检查字段、文件、语言和静态声明,绝不导入或执行包内代码,也不修改世界或存档。它复用 CLI 的校验核心;插件 CLI 遇到第一个问题就停止显示,应用会继续收集可以独立检查的问题。
报告包含 kind、可用时的 id、ok、counts.errors、counts.warnings 和 issues。每个问题有 severity、code、message,以及可用时的包内相对路径 file、字段路径或 JSON pointer field、修复提示 hint。摘要可含版本和语言。消息最多 2000 字符;保留前 200 个问题,超限时另加 issues-truncated 警告及省略数量。界面标题和已知代码按界面语言显示,其余消息保留英文;可以复制纯文本报告。
权限与安装相同,使用 host.files:托管实例需要运营者 Bearer 令牌;个人实例沿用安装接口的桌面令牌或显式启用规则。路径必须是对应插件或世界允许根目录内的真实目录,拒绝目录根的符号链接。报告把包内路径转为相对路径,把其他主机路径替换为 <path>,不返回 CLI 专用的原始文本。请求格式见 API。