第 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 安装与管理命令
# 安装(默认写入全局 ~/.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 清单:
{
"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); keywords加pi-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 扩展为例:
mkdir my-pi-pack && cd my-pi-pack
git init && npm init -y
mkdir extensions
# 把 test-guard.ts 放进 extensions/package.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"]
}
}npm publish --access public # npm 分发
# 或推到 GitHub 后用 git 分发:
git tag v1.0.0 && git push origin v1.0.0用户侧安装验证:
pi install npm:@yourname/test-guard # 或 git:github.com/yourname/test-guard@v1.0.0
pi list # 确认已装
pi # 启动后 /guard 验证命令存在13.5 过滤、启停与去重
安装后可以精细控制包加载哪些资源——设置里用对象形式替代字符串:
{
"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 包同时出现在全局和项目设置里,默认行为是?
🛠️ 动手实践
- 把第 9 章写的技能和第 11 章的扩展合并成一个 pi 包,本地用
pi install ./my-pi-pack安装验证后,再pi remove卸载。 - 用过滤配置让上面的包只加载技能、不加载扩展(
"extensions": []),用pi list与启动日志验证效果。 - 走通 git 分发:fork 或新建仓库推送包并打
v0.1.0标签,pi install git:github.com/<你>/repo@v0.1.0安装,然后改代码打v0.2.0,体验"重新 install 才能升级"的钉住语义。
完成后继续第 14 章:SDK 编程式嵌入。