Skip to content

第 13 章 · Pi Packages 包生态与分发

本章目标:掌握 pi 包的结构与 pi 清单,会用 npm 和 git 两种方式分发扩展/技能/模板/主题,并完整发布一个自己的包。

13.1 包是什么、解决什么问题

前三章我们写的扩展都散落在 ~/.pi/agent/extensions/ 里。Pi 包把 extensions、skills、prompt templates、themes 打包成一个版本化单元,通过 npm 或 git 分发,pi install 一条命令装好。官方包画廊(pi.dev/packages)收录所有带 pi-package 关键字的 npm 包。

安全提醒

包里的扩展以你的完整系统权限运行任意代码。安装第三方包前必须审查源码。

13.2 安装与管理命令

bash
# 安装(默认写入全局 ~/.pi/agent/settings.json)
pi install npm:@foo/bar@1.0.0          # npm 源(带版本号则被 update 跳过,即"钉死")
pi install git:github.com/user/repo@v1 # git 源(钉在 tag/commit)
pi install https://github.com/user/repo # 协议 URL 也直接支持
pi install /absolute/path/to/package   # 本地路径(不复制,直接引用)
pi install ./relative/path

# 临时试用:只装到临时目录,本次运行有效
pi -e npm:@foo/bar

# 管理
pi list                    # 列出 settings 里已装的包
pi remove npm:@foo/bar     # 卸载
pi update --all            # 更新 pi + 全部包 + 对齐 git 钉住的 ref
pi update --extensions     # 只更新包
pi update npm:@foo/bar     # 只更新某一个

-l 写入项目设置.pi/settings.json)而不是全局——项目设置可以随仓库共享,团队每人启动 pi 时会自动安装缺失的包(项目受信任后)。

13.3 包结构与 pi 清单

创建包最规范的方式是在 package.json 里声明 pi 清单:

json
{
  "name": "my-pi-pack",
  "version": "1.0.0",
  "keywords": ["pi-package"],
  "dependencies": {
    "zod": "^3.0.0"
  },
  "peerDependencies": {
    "@earendil-works/pi-coding-agent": "*",
    "@earendil-works/pi-ai": "*",
    "@earendil-works/pi-tui": "*",
    "typebox": "*"
  },
  "pi": {
    "extensions": ["./extensions"],
    "skills": ["./skills"],
    "prompts": ["./prompts"],
    "themes": ["./themes"],
    "image": "https://example.com/screenshot.png"
  }
}

规则要点:

  • 路径相对包根,数组支持 glob 与 ! 排除
  • 不写 pi 清单时走约定目录自动发现:extensions/(.ts/.js)、skills/(递归找 SKILL.md)、prompts/(.md)、themes/(.json);
  • keywordspi-package 才会被画廊收录;video(MP4,悬停自动播放)或 image 可加预览图。

依赖分三种,别搞混:

类型用途
dependencies第三方运行时依赖(pi 安装包时会自动 npm install,生产安装 --omit=dev,所以 devDependencies 运行时不可用
peerDependencies"*"pi 已内置的核心库(pi-ai / pi-agent-core / pi-coding-agent / pi-tui / typebox),不要打包
dependencies + bundledDependencies依赖的其他 pi 包,必须打进 tarball 并通过 node_modules/ 路径引用其资源

13.4 发布完整走查

以打包第 11 章的 test-guard 扩展为例:

bash
mkdir my-pi-pack && cd my-pi-pack
git init && npm init -y
mkdir extensions
# 把 test-guard.ts 放进 extensions/

package.json

json
{
  "name": "@yourname/test-guard",
  "version": "1.0.0",
  "description": "回合结束前自动运行测试并驱动修复",
  "keywords": ["pi-package", "pi", "testing"],
  "license": "MIT",
  "peerDependencies": {
    "@earendil-works/pi-coding-agent": "*"
  },
  "pi": {
    "extensions": ["./extensions"]
  }
}
bash
npm publish --access public          # npm 分发
# 或推到 GitHub 后用 git 分发:
git tag v1.0.0 && git push origin v1.0.0

用户侧安装验证:

bash
pi install npm:@yourname/test-guard   # 或 git:github.com/yourname/test-guard@v1.0.0
pi list                               # 确认已装
pi                                    # 启动后 /guard 验证命令存在

13.5 过滤、启停与去重

安装后可以精细控制包加载哪些资源——设置里用对象形式替代字符串:

json
{
  "packages": [
    "npm:simple-pkg",
    {
      "source": "npm:my-pi-pack",
      "extensions": ["extensions/*.ts", "!extensions/legacy.ts"],
      "skills": [],
      "prompts": ["prompts/review.md"],
      "themes": ["+themes/legacy.json"]
    }
  ]
}
  • 省略键 = 该类型全加载;[] = 全不加载;
  • !pattern 排除、+path 强制包含、-path 强制排除;过滤只做收窄,不能超出清单允许的范围。

不想改 JSON 时用交互式 pi config:Tab 在全局/项目设置间切换,可视化启停每个资源。

同一包同时出现在全局和项目设置时:项目条目胜出;若项目条目是 autoload: false,则作为全局条目之上的增量生效。身份判定:npm 看包名、git 看去掉 ref 的仓库 URL、本地看解析后的绝对路径。

本章小结

  • pi install/remove/list/update + -l 项目级安装 + -e 临时试用构成包管理闭环;
  • pi 清单声明四类资源;无清单时走约定目录;
  • 依赖三分法:运行时进 dependencies、pi 核心库进 peerDependencies: "*"、嵌套 pi 包必须 bundledDependencies
  • npm(pi-package 关键字进画廊)与 git(钉 tag,update 只对齐不前进)两种分发;
  • 对象形式过滤 + pi config 启停 + 全局/项目去重规则。

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. pi 包的运行时依赖应该声明在哪里?

2. pi install git:github.com/user/repo@v1 之后执行 pi update --extensions,钉住的 ref 会怎样?

3. 包过滤配置中 "extensions": [] 的效果是?

4. 同一个 pi 包同时出现在全局和项目设置里,默认行为是?

🛠️ 动手实践

  1. 把第 9 章写的技能和第 11 章的扩展合并成一个 pi 包,本地用 pi install ./my-pi-pack 安装验证后,再 pi remove 卸载。
  2. 用过滤配置让上面的包只加载技能、不加载扩展("extensions": []),用 pi list 与启动日志验证效果。
  3. 走通 git 分发:fork 或新建仓库推送包并打 v0.1.0 标签,pi install git:github.com/<你>/repo@v0.1.0 安装,然后改代码打 v0.2.0,体验"重新 install 才能升级"的钉住语义。

完成后继续第 14 章:SDK 编程式嵌入