npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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 格式的 Buffer

5. 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(插件管理器)会自动扫描以下目录:

  1. ~/.berrytrace/plugins/(正式版用户插件存放目录)
  2. ./plugins-dev/(开发环境插件项目目录)

任何包含已编译产物(如 dist/index.js)且拥有合规 plugin.json 的插件目录都会被主程序自动加载、激活并完成注册。

类型定义文件

本 SDK 提供了以下类型定义文件,用于 TypeScript 开发:

  1. types.ts - TypeScript 源类型定义文件(推荐用于 TypeScript 插件开发)
  2. types.d.ts - 声明文件(用于 JavaScript 插件开发,提供智能提示)
  3. 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