Kunkun

入门指南

构建、打包并加载你的第一个 Kunkun 扩展。

这篇指南会带你跑通一个最小扩展。如果你还不确定该做哪种扩展,先读 扩展类型

前置要求

  • Node.js 18+Bun
  • TypeScript 基础;如果要写 worker/node view,需要 React 基础
  • 已安装 Kunkun 桌面端

扩展长什么样

每个扩展都是一个 npm 包,并在 package.json 里声明 kunkun manifest:

{
  "name": "my-extension",
  "version": "0.1.0",
  "license": "MIT",
  "$schema": "https://schema.kunkun.sh/",
  "kunkun": {
    "identifier": "com.you.my-extension",
    "name": "My Extension",
    "permissions": ["clipboard-read"],
    "commands": [/* 一个或多个 command,每个 command 都有 mode */]
  }
}

identifier 是稳定且全局唯一的扩展 ID。每个 command 会声明运行模式(例如 custom-viewworker-viewnode-headless)和入口文件 main

扩展安装的是构建产物

Kunkun 安装扩展 tarball 后不会在安装目录里执行 npm install。你的构建产物必须自包含:把 JS 依赖打进 command/service 输出里。原生 .node addon 不能直接内联,需要把 loader 和平台文件一起打包。

快速开始:Custom-View 扩展

Custom-View 是一个静态 SPA,通过 kunkun-ext:// 协议加载到隔离窗口中。任何能编译成静态前端(SPA 或 SSG)的框架都可以使用。下面用 React 演示,因为它最普及;其他标签页是 Vue、Svelte、原生的相同步骤。

创建项目

bun create vite my-extension --template react-ts
cd my-extension
pnpm add @kunkunsh/sdk
bun create vite my-extension --template vue-ts
cd my-extension
pnpm add @kunkunsh/sdk
bun create vite my-extension --template svelte-ts
cd my-extension
pnpm add @kunkunsh/sdk
bun create vite my-extension --template vanilla-ts
cd my-extension
pnpm add @kunkunsh/sdk

如果你更习惯,npm create vite@latest / pnpm create vite 效果相同。

配置静态构建

Kunkun 从扩展自己的源加载构建产物,因此资源路径必须是相对的。在 vite.config.ts 中设置 base: './'

import { defineConfig } from 'vite'
// 框架插件:react() / vue() / svelte()
export default defineConfig({
  base: './',   // 必需:资源相对 kunkun-ext:// 加载
  // plugins: [react()],
})

使用 SvelteKit 等元框架?也可以——用 @sveltejs/adapter-static 输出静态 SPA(ssr = false、hash 路由)。详见 Custom UI 扩展

添加 manifest

Vite 已经生成了 package.json。把 $schemakunkun 字段加进这个已有的 package.json——manifest 就是 kunkun 字段本身,而不是一个单独的文件:

package.json
{
  "name": "my-extension",
  "version": "0.1.0",
  // ...Vite 生成的 scripts/dependencies
  "$schema": "https://schema.kunkun.sh/",
  "kunkun": {
    "identifier": "com.you.my-extension",
    "name": "My Extension",
    "permissions": ["clipboard-read", "clipboard-write", "storage"],
    "commands": [
      {
        "name": "main",
        "title": "My Command",
        "mode": "custom-view",
        "main": "/",
        "dist": "dist",
        "devMain": "http://localhost:5173"
      }
    ]
  }
}

接入 SDK

在入口文件中导入一次 @kunkunsh/sdk/ui/custom(在应用挂载之前),用来接通扩展与宿主的 RPC 通道;其余 API 都从 @kunkunsh/sdk 导入。

// src/main.tsx(React)/ src/main.ts(Vue、Svelte、原生)
import "@kunkunsh/sdk/ui/custom"; // 必须放在最前面
// ...照常启动应用:createRoot(el).render(<App />) / mount(App, ...) 等

构建

pnpm build   # 输出静态 SPA 到 `dist/`

快速开始:Worker-View 扩展

Worker-View 在 Web Worker 里运行一个 React 组件;由宿主根据组件树渲染 UI,从而获得一致的样式和强隔离。

初始化

mkdir my-worker-ext && cd my-worker-ext
pnpm init && pnpm add @kunkunsh/sdk react valibot
pnpm add -D @types/react @types/bun

组件 —— src/App.tsx

import { useState } from "react";
import { Button, Div, H2, P } from "@kunkunsh/sdk/ui";
import { Clipboard, showToast, Toast } from "@kunkunsh/sdk";

export default function App() {
  const [text, setText] = useState("");
  return (
    <Div className="p-6">
      <H2>My Worker Extension</H2>
      <Button title="Read Clipboard" variant="primary" onClick={async () => {
        setText(await Clipboard.readText());
        await showToast({ title: "Read!", style: Toast.Style.Success });
      }} />
      <P>Content: {text}</P>
    </Div>
  );
}

构建脚本 —— build.ts

import { dedupeReact, kunkunCommandPlugin } from "@kunkunsh/sdk/build";
import type { BunPlugin } from "bun";

await Bun.build({
  entrypoints: ["./src/App.tsx"],
  outdir: "./dist",
  target: "browser",
  format: "esm",
  minify: true,
  plugins: [kunkunCommandPlugin({ mode: "view" }) as BunPlugin, dedupeReact(import.meta.dir)],
});

Manifest + 构建

package.json
{
  "kunkun": {
    "identifier": "com.you.my-worker-ext",
    "name": "My Worker Extension",
    "permissions": ["clipboard-read", "storage"],
    "commands": [{ "name": "main", "title": "My Command", "mode": "worker-view", "main": "dist/App.js" }]
  },
  "scripts": { "build": "bun build.ts" }
}
bun run build

载入到 Kunkun

  1. 打开 Kunkun → Settings → Developer
  2. Load Extension → 选择你的扩展目录
  3. 对于自定义视图,运行 dev server(pnpm dev),Kunkun 会加载 devMain 并启用 HMR。

发布到 npm(或 jsr),用户即可从内置扩展商店安装。

探索真实示例

仓库的 extensions/ 目录里有从最简单到进阶的可运行示例:

  • uuid-generator —— 最简单的无界面命令
  • sample-headless-node / sample-headless-worker —— cron 和事件触发的后台任务
  • ffmpeg + video-processing —— 一个服务提供方和它的消费方
  • kkterminal / space-lens —— 完整的 CLI + 插件 案例

下一步

不熟悉整体架构?先读 概念 → 架构 了解你的代码到底怎么跑起来,再读 扩展如何运行 了解宿主 ↔ 插件的 RPC 模型。

On this page