berrytrace-plugin-sdk
v1.0.16
Published
SDK and scaffolding CLI for developing BerryTrace plugins
Readme
莓莓印记插件 SDK (BerryTrace Plugin SDK)
此目录包含开发 莓莓印记 (BerryTrace) 插件所需的开发工具、脚手架 CLI 以及类型定义。
快速入门指南
1. 初始化新插件项目
在您打算开发插件的目录下,运行脚手架生成器:
berrytrace-cli create my-awesome-plugin这会在 plugins-dev/my-awesome-plugin 目录中创建一套完整的全新插件项目模板。
2. 安装与构建编译
进入新创建的插件项目目录,安装开发依赖,并执行 TypeScript 代码构建:
cd plugins-dev/my-awesome-plugin
npm install
npm run build上述构建会将 TypeScript 源码编译成 dist/index.js,该入口文件已在插件的 plugin.json 中配置指定。
3. 访问 SDK
在插件中,您可以通过全局对象 berrytrace (在 TypeScript 中类型为 BerryTraceSDK) 访问所有 API:
// src/index.ts
import { Plugin, BerryTraceSDK } from 'berrytrace-plugin-sdk';
export class MyPlugin extends Plugin {
async onload(): Promise<void> {
const sdk = this.app as BerryTraceSDK;
// 获取插件信息
const info = await sdk.plugin.getInfo();
console.log('插件 ID:', info.id);
// 记录日志
await sdk.log.info('插件已加载!');
}
}4. 插件生命周期与进程模式 (onload vs activate)
由于莓莓印记采用 双进程隔离设计,插件会在渲染进程(Frontend)和主进程/后台子进程(Backend)中运行。针对这两种环境,生命周期入口也有所不同,在开发过程中请务必注意区分:
渲染进程 (Renderer Process / Frontend UI)
- 生命周期方法:
onload()与onunload() - 运行环境:沙箱 Iframe / 浏览器环境(可直接操作 DOM 与 UI,支持主题同步等)。
- 典型用途:注册侧边栏功能区图标 (
workspace.registerRibbonIcon)、注册侧边栏链接、注册视图组件 (workspace.registerView)、注册设置页的一级 Tab 等。 - 编写方式:必须继承
Plugin基类,并通过default导出:import { Plugin, BerryTraceSDK } from 'berrytrace-plugin-sdk'; export default class MyPlugin extends Plugin { async onload(): Promise<void> { const sdk = this.app as BerryTraceSDK; await sdk.log.info('UI 插件加载'); } async onunload(): Promise<void> { // 资源清理逻辑 } }
主进程 / 后台子进程 (Main / Background Process)
- 生命周期方法:
activate(sdk)与deactivate() - 运行环境:具有完整 Node.js API 能力的后端环境(Electron 主进程或独立的
utilityProcess沙箱中)。 - 典型用途:读写本地文件系统、执行系统终端命令、注册 AI 大模型 MCP 工具处理器 (
sdk.mcp.registerToolHandler)、启动后台服务等。 - 编写方式:直接导出命名的异步函数:
import { BerryTraceSDK } from 'berrytrace-plugin-sdk'; export async function activate(sdk: BerryTraceSDK) { console.log('Node 插件激活'); sdk.mcp.registerToolHandler('my_action', async (args) => { ... }); } export async function deactivate() { // 停止后台监听与命令 }
如果你的插件既有 UI 界面,又提供后台 MCP 工具,可以在不同产物模块中分别提供对应的生命周期方法,宿主主程序会自动根据其类型在相应进程里调用它们。
API 模块详解
BerryTrace SDK 提供了以下 API 模块,插件开发者可以直接通过 sdk.<模块名> 访问:
1. sdk.plugin - 插件信息 API
用于获取当前插件的元数据信息。
const info = await sdk.plugin.getInfo();
// 返回: { id, name, version, description, path }
console.log(info.name, info.version);2. sdk.log - 日志 API
提供插件日志记录功能,日志会统一输出到宿主应用的日志系统。
await sdk.log.info('这是一条信息日志');
await sdk.log.warn('这是一条警告日志');
await sdk.log.error('这是一条错误日志');
await sdk.log.debug('这是一条调试日志');3. sdk.ai - AI 功能 API
提供 AI 对话、Agent 任务执行、文本嵌入、重排序、OCR 等功能。
// AI 对话(非流式)
const response = await sdk.ai.chat({
messages: [{ role: 'user', content: '你好' }]
});
// AI 对话(流式)
await sdk.ai.chatStream(
{ messages: [{ role: 'user', content: '写一首诗' }] },
(chunk) => process.stdout.write(chunk)
);
// 运行 AI Agent 任务
const result = await sdk.ai.runAgentTask({
task: '帮我分析这个目录',
workDir: '/path/to/project'
});
console.log('会话 ID:', result.sessionId);
// 取消正在运行的 AI Agent 任务
await sdk.ai.cancelAgentTask(sessionId);
// 获取 Agent 内核状态
const status = await sdk.ai.getAgentKernelStatus();
console.log('是否运行中:', status.isRunning);
// 文本嵌入(将文本转换为向量)
const embeddings = await sdk.ai.embed(['文本1', '文本2']);
// 文本重排序(根据查询相关性排序文档)
const reranked = await sdk.ai.rerank('查询文本', ['文档1', '文档2']);
// OCR 文字识别
const ocrResult = await sdk.ai.ocr('/path/to/image.png');
console.log(ocrResult.text);4. sdk.context - 上下文 API
获取用户当前上下文信息,如活动应用、选中文本、屏幕截图等。
// 获取当前活动应用信息
const app = await sdk.context.getActiveApp();
console.log('当前应用:', app.name);
// 监听活动应用变化
const off = sdk.context.onActiveAppChanged((appInfo) => {
console.log('活动应用变为:', appInfo.name);
});
// 取消监听
off();
// 获取用户当前选中的文本
const selection = await sdk.context.getSelection();
if (selection) {
console.log('选中文本:', selection.text);
}
// 截取屏幕
const screenshot = await sdk.context.captureScreen({ target: 'screen', format: 'png' });
// screenshot 是 PNG 格式的 Buffer5. sdk.mcp - MCP (Model Context Protocol) API
允许插件注册工具和资源,供 AI Agent 调用。
// 注册 MCP 工具处理器(静态工具,需在 plugin.json 中声明)
sdk.mcp.registerToolHandler('my_plugin_search', async (args) => {
const results = await search(args.query as string);
return { content: [{ type: 'text', text: JSON.stringify(results) }] };
});
// 注册动态 MCP 工具(运行时动态注册,无需在 plugin.json 中预先声明)
await sdk.mcp.registerDynamicTool(
{
name: 'dynamic_search',
description: '动态搜索工具',
inputSchema: { type: 'object', properties: { query: { type: 'string' } } }
},
async (args) => {
return { content: [{ type: 'text', text: '搜索结果' }] };
}
);
// 取消注册动态 MCP 工具
await sdk.mcp.unregisterDynamicTool('dynamic_search');6. sdk.storage - 存储 API
提供键值对存储和简易数据库功能,数据按插件 ID 隔离存储。
// 键值对存储
await sdk.storage.kv.set('theme', 'dark');
const theme = await sdk.storage.kv.get('theme', 'light');
await sdk.storage.kv.delete('theme');
await sdk.storage.kv.clear();
// 简易数据库(类 SQL 语法)
await sdk.storage.db.execute('CREATE TABLE IF NOT EXISTS notes (id, title, content)');
await sdk.storage.db.execute('INSERT INTO notes VALUES (?, ?, ?)', [1, '标题', '内容']);
const notes = await sdk.storage.db.execute('SELECT * FROM notes');7. sdk.filesystem - 文件系统 API
提供文件读写、目录操作等功能。
// 读取文件内容
const text = await sdk.filesystem.readFile('/path/to/file.txt', 'utf-8');
const base64 = await sdk.filesystem.readFile('/path/to/image.png', 'base64');
// 读取目录内容
const items = await sdk.filesystem.readDir('/path/to/dir');
items.forEach(item => console.log(item.name, item.isDirectory ? '目录' : '文件'));
// 写入文件内容
await sdk.filesystem.writeFile('/path/to/file.txt', 'Hello World');
// 重命名/移动文件
await sdk.filesystem.renameFile('/path/to/old.txt', '/path/to/new.txt');
// 删除文件
await sdk.filesystem.deleteFile('/path/to/file.txt');
// 获取安全的系统目录路径
const dataDir = await sdk.filesystem.getSafePath('userData');
const docsDir = await sdk.filesystem.getSafePath('documents');
const desktopDir = await sdk.filesystem.getSafePath('desktop');
// 在文件管理器中显示文件
await sdk.filesystem.showItemInFolder('/path/to/file.txt');8. sdk.system - 系统 API
提供系统级功能,如主题获取、通知显示、执行系统命令等。
// 获取当前系统主题
const theme = await sdk.system.getTheme(); // 'light' 或 'dark'
// 显示系统通知
await sdk.system.showNotification({
title: '任务完成',
body: '文件已成功处理',
silent: false
});
// 在 BerryTrace 内部浏览器中打开 URL
await sdk.system.openUrl('https://example.com', {
internal: true,
width: 800,
height: 600
});
// 在系统默认浏览器中打开 URL
await sdk.system.openExternal('https://example.com');
// 执行系统命令
const result = await sdk.system.execCommand({
command: 'ls',
args: ['-la'],
cwd: '/path/to/dir',
timeoutMs: 5000
});
console.log(result.stdout);
// 等待后台命令完成
const result = await sdk.system.waitCommand({ sessionId: 'my-session' });9. sdk.dialog - 对话框 API
提供原生的文件选择对话框功能。
// 显示保存文件对话框
const saveResult = await sdk.dialog.showSaveDialog({
title: '保存文件',
defaultPath: 'my-file.txt',
filters: [{ name: 'Text', extensions: ['txt'] }]
});
if (!saveResult.canceled) {
console.log('保存路径:', saveResult.filePath);
}
// 显示打开文件对话框
const openResult = await sdk.dialog.showOpenDialog({
title: '选择文件',
properties: ['openFile', 'multiSelections'],
filters: [{ name: 'Images', extensions: ['jpg', 'png'] }]
});
if (!openResult.canceled) {
console.log('选中文件:', openResult.filePaths);
}10. sdk.workspace - 工作区 API
用于操作 BerryTrace 的工作区,如注册视图、操作标签、注册功能区图标等。
// 注册功能区图标(侧边栏图标)
sdk.workspace.registerRibbonIcon(
'my-plugin:open',
'🚀',
'Open My Plugin',
() => sdk.window.createFloatWindow({ url: '...' })
);
// 取消注册功能区图标
sdk.workspace.unregisterRibbonIcon('my-plugin:open');
// 获取当前工作区路径
const workspacePath = await sdk.workspace.getPath();
// 获取当前工作区元数据
const metadata = await sdk.workspace.getMetadata();
// 在工作区打开标签页
sdk.workspace.openWorkspaceTab('/path/to/file.txt', 'my-plugin');11. sdk.commands - 命令 API
允许插件注册命令,用户可通过命令面板调用。
// 注册命令
const cmdId = sdk.commands.register({
id: 'my-plugin.hello',
name: 'Say Hello',
icon: '👋',
handler: () => sdk.log.info('Hello!')
});
// 取消注册命令
sdk.commands.unregister(cmdId);
// 执行命令
const result = await sdk.commands.execute('my-plugin.hello');12. sdk.events - 事件 API
插件间通信的核心机制,基于发布-订阅模式。
// 监听事件(持续监听,直到取消)
const off = sdk.events.on('my-plugin:data-updated', (data) => {
console.log('数据已更新:', data);
});
// 取消监听
off();
// 监听事件(仅触发一次)
sdk.events.once('my-plugin:init', (data) => {
console.log('初始化完成:', data);
});
// 发射事件(通知所有监听者)
sdk.events.emit('my-plugin:data-updated', { id: 123, name: 'test' });
// 取消监听事件
// 注意:需要保存处理函数引用才能取消13. sdk.scheduler - 调度器 API
允许插件注册定时或周期性执行的任务。
// 每 5 分钟执行一次
await sdk.scheduler.register({
id: 'my-plugin:sync',
intervalMs: 5 * 60 * 1000,
command: 'node',
args: ['sync.js']
});
// 使用 cron 表达式,每天早上 9 点执行
await sdk.scheduler.register({
id: 'my-plugin:daily',
cron: '0 9 * * *',
command: 'node',
args: ['daily.js']
});
// 取消注册调度任务
await sdk.scheduler.unregister('my-plugin:sync');
// 列出当前插件注册的所有调度任务
const tasks = await sdk.scheduler.list();注册 MCP 工具 (MCP Tools)
在您的插件清单文件 plugin.json 中,声明您想要暴露给 LLM 智能体的工具(Tools):
{
"mcp": {
"tools": [
{
"name": "my_tool_name",
"description": "执行某种逻辑的说明...",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
}在插件的入口源码 src/index.ts 中,绑定该工具的具体执行处理器:
sdk.mcp.registerToolHandler('my_tool_name', async (args) => {
const query = args.query;
// 在此处编写您的业务逻辑代码
return {
content: [{ type: 'text', text: `查询结果为: ${query}` }]
};
});运行与测试插件
当您在开发模式下启动莓莓印记(BerryTrace)主应用程序时,内部的 PluginManager(插件管理器)会自动扫描以下目录:
~/.berrytrace/plugins/(正式版用户插件存放目录)./plugins-dev/(开发环境插件项目目录)
任何包含已编译产物(如 dist/index.js)且拥有合规 plugin.json 的插件目录都会被主程序自动加载、激活并完成注册。
类型定义文件
本 SDK 提供了以下类型定义文件,用于 TypeScript 开发:
types.ts- TypeScript 源类型定义文件(推荐用于 TypeScript 插件开发)types.d.ts- 声明文件(用于 JavaScript 插件开发,提供智能提示)types.js- JavaScript 存根文件(提供运行时的最小化实现)
在 TypeScript 插件项目中,您可以在 tsconfig.json 中配置:
{
"compilerOptions": {
"types": ["berrytrace-plugin-sdk/types"]
}
}或者直接导入类型:
import { Plugin, View, BerryTraceSDK, LogAPI } from 'berrytrace-plugin-sdk/types';示例插件
以下是一个简单的示例插件,展示如何使用这些 API:
// src/index.ts
import { Plugin, BerryTraceSDK } from 'berrytrace-plugin-sdk';
export class MyPlugin extends Plugin {
async onload(): Promise<void> {
const sdk = this.app as BerryTraceSDK;
// 记录日志
await sdk.log.info('我的插件已加载!');
// 获取插件信息
const info = await sdk.plugin.getInfo();
await sdk.log.info(`插件名称: ${info.name}, 版本: ${info.version}`);
// 注册命令
sdk.commands.register({
id: 'my-plugin:hello',
name: 'Say Hello',
icon: '👋',
handler: async () => {
await sdk.log.info('Hello from my plugin!');
await sdk.system.showNotification({
title: 'My Plugin',
body: 'Hello World!'
});
}
});
// 注册功能区图标
sdk.workspace.registerRibbonIcon(
'my-plugin:open',
'🚀',
'Open My Plugin',
() => {
sdk.window.createFloatWindow({
url: 'https://example.com',
width: 800,
height: 600
});
}
);
}
async onunload(): Promise<void> {
const sdk = this.app as BerryTraceSDK;
await sdk.log.info('我的插件已卸载!');
// 取消注册命令和图标
sdk.commands.unregister('my-plugin:hello');
sdk.workspace.unregisterRibbonIcon('my-plugin:open');
}
}npx tsc -p plugins-sdk
