核心概念
权限
Kunkun 基于能力的权限模型——声明、限定范围、请求及其执行方式。
扩展在其清单中声明所需的能力。用户在安装时批准这些能力;某些敏感操作还会在运行时额外提示。权限执行始终在主机端进行——绝不发生在你的插件代码中。
两种权限形式
简单权限——没有作用域的能力:
{ "kunkun": { "permissions": ["clipboard-read", "storage", "notifications"] } }限定范围的权限——包含允许/拒绝列表或域名列表的对象:
{
"permission": "fs-read",
"allow": ["$EXTENSION_SUPPORT/**", "$HOME/Documents/**"],
"deny": ["$HOME/Documents/Private/**"]
}权限目录
| 权限 | 控制内容 | 作用域形式 |
|---|---|---|
clipboard-read / clipboard-write | 剪贴板读取 / 写入 | — |
storage | KV 存储 以及 记录存储 | — |
notifications | 系统通知 | — |
fs-read / fs-write | 文件 I/O | allow / deny glob 数组 |
network | fetch | domains glob 数组 |
shell | 命令 / 脚本执行 | commands: [{ program, args? }] 或 scripts |
open-url / open-file / open-folder | 用默认应用打开 | allow / deny |
system-open / system-trash / system-finder / system-applications / system-selected-text | 系统集成 | — |
dialog | 原生文件/保存/消息对话框 | — |
window-control | 调整大小/移动/毛玻璃效果等 | — |
path | 路径工具与别名 | — |
ai | 插件 AI API | — |
services | 发现/调用其他扩展的服务 | — |
backend | 生成受管理的后端进程 | allow: [{ script, runtime?, capabilities? }] |
input-monitor | 键盘/鼠标事件订阅 | — |
路径别名
作用域使用由主机解析的跨平台别名:
| 别名 | 解析为 |
|---|---|
$HOME | 用户主目录 |
$DESKTOP / $DOWNLOAD / $DOCUMENT | 标准用户文件夹 |
$EXTENSION | 你的安装目录(只读) |
$EXTENSION_SUPPORT | 你的可写数据目录 |
Glob 模式:**(递归)、*(单层)、*.ext(扩展名匹配)。
最小权限原则
建议对自己的数据使用 $EXTENSION_SUPPORT/**,并请求尽可能狭窄的作用域。宽泛的 $HOME/** 访问是审核者(和用户)会注意到的危险信号。
运行时(动态)授权
某些能力最好在即将需要之前请求,限定在用户当前操作范围内:
import { permissions } from "@kunkunsh/sdk";
const granted = await permissions.request(
"fs-read",
"$HOME/Documents/**",
"导入你选择的文件", // 在提示中显示
);
if (granted) { /* … */ }- 允许一次 → 存储在会话映射中,窗口关闭时清除。
- 始终允许 → 持久化到
permission_grants表中,用户可在设置中撤销。 - 拒绝 → 返回
false。
permissions.check(type, scope) 是一种预检查询——不是授权边界。始终让主机来强制执行。
执行机制
注意限定了文件系统检查范围的操作会在匹配前解析符号链接,因此符号链接无法绕过你的允许列表走私访问。
服务权限交集
当扩展 A 调用扩展 B 的服务时,有效权限会安全地组合:
- 调用者的资源权限(fs、network、open-*)针对用户选择的资源保持不变。
- 提供者的实现权限(例如提供者对
ffmpeg的限域shell访问)由提供者提供,因此调用者无需声明提供者的私有细节。 - 其他所有内容需要双方都有权限。
这防止了权限提升:低权限的扩展无法通过调用高权限的服务来获得能力。
Raycast 兼容性策略
导入的 Raycast 扩展在更严格的策略下运行。每个主机方法被标记为 raycast-allowed 或 kunkun-only;对于 Raycast 来源的插件,即使命名空间被导入,Kunkun 专属的 API(例如 shell.spawn)也会被拒绝。原生 Kunkun 扩展获得完整的表面(仍需遵守清单权限)。
进程沙箱
对于 Node 模式和后端,主机从清单中派生出运行时标志:
| 运行时 | 沙箱 |
|---|---|
| Deno(推荐) | --allow-read/--allow-write 限定到你的路径,按声明的域 --allow-net=domain,限域的 --allow-run/--allow-ffi/--allow-env/--allow-sys |
| Node.js v25+ | Node 权限标志;全量 env/sys 隐式满足(Node 不拦截),但限定的 env/sys/subprocess、域限定网络和 FFI 被拒绝,除非声明了 capabilities.unsandboxed |
| Bun | 拒绝,除非声明了 capabilities.unsandboxed(Bun 没有沙箱) |
你的安装目录是只读的;你的支持目录是可写的。参见后端进程了解如何生成受管理的子进程。
检查清单
- 请求最小权限;严格限定文件系统/网络的范围。
- 使用
$EXTENSION_SUPPORT存储你自己的数据。 - 在运行时请求敏感作用域,并附上明确的原因。
- 优雅地处理拒绝——在操作前检查,降级而非崩溃。
- 在 README 中记录为什么你需要每个权限。