uTools 插件开发指南
参考资源
完整 API 文档位于 references/utools-api.md中。
查阅规则:本 skill 只提供规范和索引。当需要任何 uTools API 的具体签名、参数、返回值、类型定义时,必须用 Read 工具读取 references/utools-api.md 的对应章节,不要凭记忆猜测 API 用法。
激活契约
当本 skill 激活时,AI 必须遵守以下全局规则:
- 查文档优先:不确定的 API → 读
references/utools-api.md,不要编造 - 区分 dev/build 模式:开发时用
public/(HMR),发布时用dist/(构建产物) - preload 透明:preload 代码必须源码可读,不压缩不混淆
- DB 合规:
utools.db只存用户主动创建的数据,禁止存缓存/日志/临时状态 - 平台兼容:preload 里用
path.join(),不硬编码路径分隔符
项目模板
uTools 插件支持任意前端框架,只要编译产物是纯 HTML/CSS/JS。以下是 Vue3 和 React 两套模板的规范。
通用目录结构(两套模板共享)
项目根目录/
├── public/ # ← uTools 接入开发的目录(plugin.json 在这里)
│ ├── plugin.json
│ ├── logo.png # 建议 256×256 PNG
│ └── preload/
│ ├── services.js # preload 脚本(CommonJS,不压缩)
│ └── package.json # {"type":"commonjs"}
├── src/ # 前端源码
├── dist/ # npm run build 产物(发布版)
├── vite.config.js # Vite 配置(base: './' + stripDevelopmentField 插件)
├── package.json
└── jsconfig.json # 类型提示(types: ["utools-api-types"])
Vue 3 + Vite 模板
package.json 关键依赖:
{
"type": "module",
"dependencies": { "vue": "^3.5.13" },
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.1",
"utools-api-types": "^7.5.1",
"vite": "^6.0.11"
}
}
vite.config.js:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import fs from 'node:fs'
import path from 'node:path'
function stripDevelopmentField() {
return {
name: 'strip-development-field',
closeBundle() {
const p = path.join(process.cwd(), 'dist', 'plugin.json')
if (!fs.existsSync(p)) return
const json = JSON.parse(fs.readFileSync(p, 'utf-8'))
delete json.development
fs.writeFileSync(p, JSON.stringify(json, null, 2) + '\n', 'utf-8')
},
}
}
export default defineConfig({
plugins: [vue(), stripDevelopmentField()],
base: './',
})
入口 src/main.js:
import { createApp } from 'vue'
import './main.css'
import App from './App.vue'
createApp(App).mount('#app')
React + Vite 模板
package.json 关键依赖:
{
"type": "module",
"dependencies": { "react": "^19.0.0", "react-dom": "^19.0.0" },
"devDependencies": {
"@vitejs/plugin-react": "^4.3.4",
"utools-api-types": "^7.5.1",
"vite": "^6.0.11"
}
}
vite.config.js:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import fs from 'node:fs'
import path from 'node:path'
function stripDevelopmentField() {
return {
name: 'strip-development-field',
closeBundle() {
const p = path.join(process.cwd(), 'dist', 'plugin.json')
if (!fs.existsSync(p)) return
const json = JSON.parse(fs.readFileSync(p, 'utf-8'))
delete json.development
fs.writeFileSync(p, JSON.stringify(json, null, 2) + '\n', 'utf-8')
},
}
}
export default defineConfig({
plugins: [react(), stripDevelopmentField()],
base: './',
})
入口 src/main.jsx:
import React from 'react'
import { createRoot } from 'react-dom/client'
import './main.css'
import App from './App.jsx'
createRoot(document.getElementById('app')).render(<App />)
index.html 需要把 script 改为 jsx:
<script type="module" src="/src/main.jsx"></script>
两套模板的 App 组件入口模式
无论 Vue 还是 React,入口组件都必须在 onMounted(Vue)或 useEffect(React)中注册 utools.onPluginEnter 回调,接收 action.code 做功能路由。
核心规范
plugin.json
{
"main": "index.html",
"preload": "preload/services.js",
"logo": "logo.png",
"pluginSetting": {
"single": true,
"height": 600
},
"development": {
"main": "http://localhost:5173"
},
"features": [
{
"code": "feature-code",
"explain": "功能描述",
"cmds": ["关键词1", "关键词2"]
}
]
}
字段约束:
- main:相对 plugin.json 的路径,必须 .html,必填
- preload:相对路径,可选,但几乎所有实用插件都需要
- development.main:仅开发期,指向 vite dev server(默认 http://localhost:5173),发布时必须不存在——由 stripDevelopmentField vite 插件自动处理
- features[].code:功能编码,必须唯一,进入插件时通过 onPluginEnter 的 action.code 获取
- features[].cmds:指令集合,支持字符串(功能指令)和对象(匹配指令)两种
cmds 指令类型(具体写法查 references/utools-api.md 的"匹配指令"章节):
- 功能指令(字符串):搜索框直接搜索打开,中文自动支持拼音
- regex:正则匹配文本
- over:匹配任意文本(超级面板)
- img:匹配图片
- files:匹配文件/文件夹
- window:匹配活动窗口
dev/build 双模式
| 模式 | plugin.json | 接入目录 | 依赖 |
|---|---|---|---|
| HMR(开发) | 保留 development.main |
public/ |
dev server 运行 |
| 构建(发布) | 无 development |
dist/ |
无 |
stripDevelopmentField vite 插件确保 npm run build 后 dist/plugin.json 自动干净。AI 创建项目时必须配置此插件。
dist/ 是 build 自动产物(public/ 镜像 + 编译后的 assets/),AI 不需要手动维护。如果用户报告"插件打不开",检查 dist/ 是否缺少 plugin.json、logo.png、preload/ 这几个 public/ 下应有的文件。
preload 规范(铁律)
- CommonJS 规范:用
require/module.exports,不能用 ES module - 源码透明:不打包、不压缩、不混淆,审核会检查
- 依赖位置:第三方 npm 包放在
preload/同级目录的node_modules,不编译 - package.json:
preload/目录下必须有{"type":"commonjs"} - 能力暴露:通过
window.xxx = {...}注入渲染进程 - 最小权限:只暴露必要的函数,不要把整个
fs模块暴露
preload 示例:
const fs = require('node:fs')
const path = require('node:path')
window.services = {
readFile(filePath) {
return fs.readFileSync(filePath, { encoding: 'utf-8' })
},
writeFile(filePath, content) {
fs.writeFileSync(filePath, content, { encoding: 'utf-8' })
return filePath
},
}
utools.db 使用红线
utools.db(同步数据库,跨设备同步)——只允许存:
- 用户主动创建的内容(笔记、收藏、文档)
- 用户主动修改的配置
- 需要跨设备保持一致的数据
禁止存入 utools.db:
- 缓存、运行状态、临时配置
- 日志、统计计数、访问记录
- 缩略图、搜索索引等可重新生成的数据
- 剪贴板数据、系统监听数据
违反此红线会导致插件被下架。临时数据用 utools.dbStorage(不同步)或内存变量。
db 操作要点:具体 API 签名(put/get/remove/allDocs/bulkDocs/附件)和 _rev 机制查 references/utools-api.md 的"本地数据库"章节。关键设计建议:用 _id 前缀组织文档分类,一条记录一个文档以避免多设备冲突。
API 分类索引
以下只列大类,具体 API 签名和用法必须查 references/utools-api.md 对应章节:
| 分类 | 说明 | 查阅章节 |
|---|---|---|
| 事件 | 插件生命周期回调(进入/退出/分离/同步) | "事件" |
| 窗口 | 主窗口控制、子输入框、独立窗口创建 | "窗口" |
| 复制 | 文本/图片/文件复制到剪贴板 | "复制" |
| 输入 | 向外部应用粘贴文本/图片/文件 | "输入" |
| 系统 | 通知、文件操作、路径获取、系统信息 | "系统" |
| 屏幕 | 取色、截图、显示器信息 | "屏幕" |
| 用户 | 获取用户信息、临时 token | "用户" |
| 动态指令 | 运行时增删 feature | "动态指令" |
| 模拟按键 | 键盘/鼠标模拟 | "模拟按键" |
| AI | 调用 uTools 内置 AI 能力 | "AI" |
| FFmpeg | 音视频处理 | "FFmpeg" |
| 本地数据库 | utools.db 文档型 CRUD |
"本地数据库" |
| dbStorage | KV 存储封装 | "dbStorage" |
| dbCryptoStorage | 加密 KV 存储 | "dbCryptoStorage" |
| 可编程浏览器 | ubrowser 链式 API | "可编程浏览器" |
| 用户付费 | 付费/支付/订单 | "用户付费" |
平台注意事项
Windows 特有
- PowerShell 启动 npm:用
Start-Process时必须用npm.cmd,不能用npm(后者可能被解析为其他程序,如 Notepad4) - 路径分隔符:preload 里用
path.join()而非字符串拼接,Windows 是\,macOS/Linux 是/ type: "window"的class字段:仅 Windows 有效(窗口类名),macOS/Linux 忽略- PowerShell 输出编码:中文可能乱码,不影响功能,只影响终端显示
macOS 特有
- 应用路径:
type: "window"的app字段用.app后缀(如Safari.app) - 窗口样式:
titleBarStyle可选hidden/hiddenInset/customButtonsOnHover
Linux 特有
- 部分 API 不支持:
readCurrentFolderPath/readCurrentBrowserUrl在 Linux 上不可用 - 文件管理器:在文件管理器中显示文件的 API 行为依赖发行版的文件管理器
跨平台通用
- 获取系统标准路径(downloads/desktop/home 等):查"系统"章节的
getPathAPI - 平台判断:查"系统"章节的
isMacOS/isWindows/isLinuxAPI - 暗色模式:优先用 CSS
prefers-color-schememedia query,JS 判断查"系统"章节的isDarkColorsAPI
AI 行为准则
当本 skill 激活时,AI 在写 uTools 插件代码时必须遵守:
必须做
- 创建项目时配置
stripDevelopmentFieldvite 插件,确保 build 产物干净 - vite.config.js 设置
base: './',否则资源路径错误 - preload 保持源码可读,不引入打包工具处理 preload
- preload 同级目录放
package.json,声明"type": "commonjs" - 用
path.join()处理路径,不硬编码分隔符 utools.db文档用前缀_id(如memo/<timestamp>),便于按前缀批量查询- 更新 db 文档时带版本字段,否则更新失败(具体字段名查文档)
- 入口组件注册
onPluginEnter,接收 action 做功能路由 - 需要具体 API 时读
references/utools-api.md,不凭记忆猜
禁止做
- 禁止把缓存/日志/临时数据写入
utools.db(会导致下架) - 禁止在 preload 中使用 ES module 语法(
import/export) - 禁止压缩/混淆 preload 代码
- 禁止在发布版 plugin.json 中保留
development字段 - 禁止在发布版中加载外部网络资源(
http:///https://),开发期可以 - 禁止把整个
fs模块暴露给渲染进程(最小权限原则) - 禁止凭记忆编写 uTools API 调用,必须查文档
- 禁止在
@media块内使用&::嵌套选择器(原生 CSS 不支持,用 CSS 变量代替)