打包、测试并复用扩展
通过独立资源包、真实加载器和分层验证,把本地扩展变成可检查的交付物。
打包、测试并复用扩展
扩展在源码目录里能运行,打包后却加载失败,通常与模型无关:入口文件没进包、相对依赖丢失,或宿主库被重复打进产物。分发验证应从实际包文件开始。
本文把工具样例做成独立资源包,同时保留其他阶段的练习文件。资源清单只激活 tools.ts,防止同名工具被重复注册。
本文示例固定使用 @earendil-works/pi-coding-agent@1.5.0,源码位于仓库 columns/coding-agent/examples/extension-development/。示例是独立包,先在该目录安装依赖;不需要修改专栏站点依赖。下面的命令均从这个示例目录运行。
包清单声明的是资源入口
示例的关键清单如下,完整版本见示例目录 package.json:
{
"name": "agent-extension-lessons",
"version": "0.0.0",
"private": true,
"type": "module",
"files": ["extensions", "src", "fixtures", "test"],
"pi": { "extensions": ["./extensions/tools.ts"] },
"peerDependencies": {
"@earendil-works/pi-coding-agent": "1.5.0",
"@earendil-works/pi-schema": "1.5.0"
}
}files 决定 npm 包包含什么,pi.extensions 决定宿主把什么当作扩展入口,两者不能混用。工具入口引用 src/register-inspection.ts 和 src/inspect.ts,这些辅助文件也要进入产物。fixtures 用来让教学包可复现,真实扩展应明确它读取调用者项目还是包内资源,不能默认二者路径相同。
宿主 API 采用 peer 依赖,开发目录另用固定 dev 依赖做类型检查。不要把宿主运行时整个 bundle 进扩展,再期待其中的对象身份、模块单例和资源管理自动与真实宿主一致。本包设为 private,教程不需要 npm 发布。
直接调用真实加载器
src/audit.ts 在临时工作目录和 agent 配置目录中加载指定路径,避免读入个人扩展配置。扩展本身仍以进程权限执行;临时目录是配置隔离,不是代码沙箱。
import { mkdtemp, rm } from "node:fs/promises"
import { tmpdir } from "node:os"
import { resolve } from "node:path"
import { discoverAndLoadExtensions } from "@earendil-works/pi-coding-agent"
const scratch = await mkdtemp(resolve(tmpdir(), "extension-audit-"))
try {
const file = resolve(process.argv[2] || "extensions/tools.ts")
const result = await discoverAndLoadExtensions([file], scratch, resolve(scratch, "agent"))
console.log(
JSON.stringify(
{
errors: result.errors,
extensions: result.extensions.map((extension) => ({
tools: [...extension.tools.keys()],
commands: [...extension.commands.keys()],
events: [...extension.handlers.keys()],
})),
},
null,
2,
),
)
if (result.errors.length > 0 || result.extensions.length !== 1) {
process.exitCode = 1
}
} finally {
await rm(scratch, { recursive: true, force: true })
}npm run typecheck
npm run audit -- extensions/tools.ts
npm pack --dry-run --json --ignore-scripts应看到注册工具 lesson_inspect、命令 lesson-check,errors 为空;pack 的文件清单应包含入口及其相对导入。开发时使用 jiti 加载 .ts 及其本地 .js 导入映射,仍要通过真实 loader 验证,不能只看 tsc。
分层测试各自证明什么
测试工具参数时至少包括合法路径、无效路径、缺失文件、超大文件和取消;测试事件时同时验证合法调用没有被误拦。不要只判断函数返回某个对象,还要检查拒绝路径有没有触碰文件或留下资源。
从本地路径安装到复用
在隔离练习项目里可以用 pi install /绝对路径/extension-development --local 记录本地资源包,再重新启动检查工具清单。不要一开始就安装进用户级配置,否则会污染其他项目,也让“为什么加载了两个同名工具”更难解释。
更新后先检查包内容,再加载,再走业务与宿主交互。多资源包可以包含 extensions、skills、prompts 和 themes,但它们各有发现与使用机制。Skill 不会因为同包就自动执行脚本,主题也不会自动赋予扩展新的权限。
本系列的机器检查记录在仓库 research/extension-development-verification.md。未做的模型、终端和跨平台验证应保留为明确的验收项,不能由加载清单替代。
依据与版本
代码以已发布的 1.5.0 包导出、类型声明和加载器为准。在线主分支会继续变化,遇到接口差异时先核对版本。