piagent_
← ~/guides

发布扩展

最后更新: 2026年8月7日

$ pi –publish

TL;DR. 本地优先:把文件丢进 ~/.pi/agent/extensions/.pi/extensions/,或用 pi -e ./my-extension.ts 快速试;/reload 热加载。要分发就发一份 package.json,带上 pi: { extensions: [...] } 字段指向编译后的 JS,并把所有运行期依赖放进 dependencies(不能放 devDependencies —— Pi 用 --omit=dev 安装)。npm link + pi install link: 验证,再发布到 npm 或推到 git 主机通过 pi install git:... 安装。扩展以完整系统权限运行 —— 在 README 里写清楚你用到什么权限。

Pi 扩展最初就是一个 TypeScript 文件。当你想让别人 —— 或者跨多台机器的未来的自己 —— 通过 pi install 装上它时,它就升级为一个可分发的包。本文覆盖扩展包的结构、package.json 里的 pi 字段、发布前的本地测试,以及围绕运行期依赖的几个坑。事实依据是 Extensions 文档Packages 文档,以及 packages/coding-agent/examples/extensions 下的可运行示例。

最小可用的扩展

在操心打包之前,先确保你的扩展能作为单文件跑起来。最小的实用形态:

import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";

export default function (pi: ExtensionAPI) {
  pi.registerTool({
    name: "greet",
    label: "Greet",
    description: "Say hello to someone",
    parameters: Type.Object({
      name: Type.String({ description: "Name to greet" }),
    }),
    async execute(_id, params) {
      return {
        content: [{ type: "text", text: `Hello, ${params.name}!` }],
        details: {},
      };
    },
  });
}

存为 greet.ts,无需安装即可测试:

pi -e ./greet.ts

TUI 里 LLM 现在能用 name 参数调用 greet 工具。可用工具列表里会看到它已被注册。

扩展发现路径

本地开发时,Pi 自动从以下位置拾取 .ts 文件:

  • ~/.pi/agent/extensions/*.ts —— 全局,单文件
  • ~/.pi/agent/extensions/*/index.ts —— 全局,子目录
  • .pi/extensions/*.ts —— 项目级,单文件
  • .pi/extensions/*/index.ts —— 项目级,子目录

项目级扩展只在项目被信任后才会被加载(通过 project_trust 事件解析)。/reload 可在不重启的情况下重新加载。

对于非标准路径 —— 你自己的临时目录、某人的 checkout —— 在 settings.json 里列出来:

{
  "extensions": [
    "/path/to/local/extension.ts",
    "/path/to/local/extension/dir"
  ]
}

把文件升级为包

当扩展超过单个文件、或者需要第三方依赖时,就该打包了。最小的 package.json 长这样:

{
  "name": "pi-greet",
  "version": "0.1.0",
  "description": "为 Pi 添加 greet 工具。",
  "type": "module",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "dependencies": {
    "typebox": "^0.32.0",
    "@earendil-works/pi-coding-agent": "^0.83.0"
  },
  "pi": {
    "extensions": ["./dist/index.js"]
  }
}

两个容易踩坑的细节:

  • pi.extensions 是入口清单。它指向编译后的 JS(不是 TS 源码),这样 Pi 在运行期无需 TypeScript 工具链即可加载。
  • 写在 dependencies,不是 devDependencies 包安装默认走生产安装(npm install --omit=dev),所以任何运行期 import 的东西都必须放在 dependencies

可选地,在 @earendil-works/pi-coding-agent 上声明 peerDependencies 是推荐做法 —— 它由 Pi 自身提供。宽松钉版本(^0.83.0)能避免用户在各自升级 Pi 时出现版本冲突。

发布前测试包

推到 npm 之前,先把包本地 link 起来,让 pi install 本地路径与终端用户安装的方式完全一致:

# 在扩展仓库内
npm link

# 全局可见;在任意项目里测试
pi install link:pi-greet

# 或者直接指向编译后的目录
pi -e /absolute/path/to/pi-greet/dist/index.js

link 完成后,覆盖每个入口点:注册工具、订阅会话事件、渲染自定义 UI。/reload 验证热重载,重新启动 Pi 验证冷启动也能加载。

发布到 npm

标准 npm 发布流程即可:

npm login
npm publish --access public

确保 dist/ 是最新的(用你偏好的工具编译 TypeScript —— tsctsupunbuild),package.json 列全所有运行期依赖,并通过 files 字段(或 .npmignore)把 source map 与开发产物挡在 tarball 外。

发布后,在新 shell 里安装验证:

pi install npm:pi-greet
pi

新会话里 greet 工具应当与本地测试时一样可用。

发布到 git 托管平台

Git 包适合私有 fork 或钉到某个具体 commit。包本身仍需要带 pi 字段的 package.json,用户这样安装:

pi install git:github.com/your-org/pi-greet@v1.0.0

Packages 文档覆盖支持的 URL 形态,以及如何指向 monorepo 中的子目录。注意:配置了 npmCommand 时,git 安装走普通的 npm install(而非 --omit=dev),所以包装器与有 hoisted 依赖的 monorepo 都能正常工作。

可以基于哪些包构建

扩展作者可以引用几个官方包:

用途
@earendil-works/pi-coding-agent 扩展类型(ExtensionAPIExtensionContext、events)
typebox 工具参数的 JSON Schema 定义
@earendil-works/pi-ai AI 工具(StringEnum 等 Google 兼容枚举)
@earendil-works/pi-tui 自定义渲染用的 TUI 组件

如果你的包是要新增一个自定义 provider,而不是只新增工具,看 Custom providers 文档。完整 provider 扩展接口(注册、模型刷新、过滤、自定义流式)在 v0.81.0 引入。

权限、信任与披露

Pi 扩展以你的完整系统权限运行,可以执行任意代码。agent 不做沙箱,所以安装信任模型就是“谁发布包谁负责代码”。两条实践能保护用户、也提升你包的可信度:

  1. 在 README 里写明扩展需要的权限。 如果你访问网络、在工作目录外写文件、或调用子进程,都写清楚。
  2. 入口面尽量收窄。 单条 pi.extensions 入口重新导出所有内容,比一片铺开的副作用 import 更容易审计。

项目级扩展由 project_trust 事件把关 —— 在用户显式信任之前,扩展不会在新克隆的仓库里自动加载。

一份精简的发布清单

在打 1.0.0 tag 之前:

  • package.jsonnameversiondescriptiontype: "module"pi.extensions,以及所有运行期依赖。
  • npm pack --dry-run 只列出你打算发布的文件。
  • 在干净目录里 npm install 产出能用的包。
  • 在新 Pi 会话里 pi install npm:your-package 能加载扩展。
  • README 写明安装、配置以及扩展使用的权限。
  • 版本相对 @earendil-works/pi-coding-agent 钉好,避免 API 变更时的破坏性升级。

想在生态里更显眼一点,可以在本站资源地图的 extensionstools 分类下提交一条 —— 见 Contributing 页面的 schema 与提交流程。

延伸阅读