贯穿项目最后一击:用 M04 学的扩展能力,把
md-tools 注册成 Pi 的 /md 斜杠命令和一个可被模型调用的 md_tools 工具,并跑通完整链路。至此,入门课的脚本被彻底「升级」成 Pi 的一等公民。目标:扩展把 md-tools 接进 Pi
我们要写一份扩展,做三件事:
pi.registerTool注册md_tools工具,模型可直接调用pi.registerCommand注册/md斜杠命令,人可直接用- 用
tool_call事件给rename加确认(安全)
这份扩展调用你上一节打包的脚本,也就是把 md-tools 脚本「暴露」给 Pi。
第一步:完整扩展骨架
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";
import { StringEnum } from "@earendil-works/pi-ai";
export default function (pi: ExtensionAPI) {
// 1) 工具:模型可直接调用
pi.registerTool({
name: "md_tools",
label: "MD Tools",
description: "处理 markdown 文件:stats 统计、convert 转纯文本、rename 改名(先预览)",
parameters: Type.Object({
action: StringEnum(["stats", "convert", "rename"] as const),
path: Type.String({ description: "目标 markdown 文件" }),
}),
async execute(toolCallId, params) {
const result = await pi.exec("node", ["./scripts/index.js", params.action, params.path]);
return {
content: [{ type: "text", text: result.stdout }],
details: { code: result.code },
};
},
});
// 2) 命令:人用 /md
pi.registerCommand("md", {
description: "用 md-tools 处理 markdown 文件",
handler: async (args, ctx) => {
ctx.ui.notify(`md-tools: ${args}`, "info");
},
});
// 3) 安全:rename 前确认
pi.on("tool_call", async (event, ctx) => {
if (event.toolName === "md_tools" && event.input.action === "rename") {
const ok = await ctx.ui.confirm("改名?", `确认对 ${event.input.path} 改名吗?`);
if (!ok) return { block: true, reason: "用户取消改名" };
}
});
}
注意 pi.exec 是执行 shell 命令的 API(返回 stdout / stderr / code),用它把脚本的输出接回来。
第二步:放到自动发现目录
官方提醒过:放自动发现目录才能 /reload 热重载。所以别只做 pi -e ./x.ts 的临时测试,要正式放到:
~/.pi/agent/extensions/my-md-tools.ts # 全局,所有项目生效
或项目级 .pi/extensions/(需信任)。放好启动,扩展就自动加载。
第三步:跑通整条链路
启动后,验证三件事:
# 1) 模型能否调用工具:直接问它
"用 md_tools 检查 README.md 的统计信息"
# 2) 斜杠命令是否可用:输入
/md stats README.md
# 3) 改名是否走确认:让模型执行 rename
"用 md_tools 把 a.md 改名为 b.md" # 应弹出确认
一条条验证,别一起跑。工具、命令、安全拦截,三条链路各自确认通了,才算真的跑通。
落地练习:完整验收 md-tools 扩展
- 把上面扩展放进
~/.pi/agent/extensions/,重启 Pi - 让模型调用
md_tools工具,确认统计输出正确 - 输入
/md stats确认命令可用 - 让模型执行
rename,确认会先弹确认框 - 修改扩展代码,用
/reload验证热重载生效
怎么判断做对了?——工具、命令、安全拦截三条都通,
/reload后新逻辑生效。
卡住了怎么办? 工具不通 → 检查 parameters schema、脚本路径。命令不通 → 检查 registerCommand。安全拦截不触发 → 检查 event.toolName 是不是 md_tools、event.input.action 取值。
常见坑:pi -e 测完就完事,忘了放正式位置
很多人在 pi -e ./x.ts 里测通了就收工,结果下次启动(不带 -e)扩展没了——因为没放进自动发现目录。
官方明确:-e 只适合快速测试;要自动加载、要能 /reload,就放进 ~/.pi/agent/extensions/(全局)或 .pi/extensions/(项目)。 测试和落地是两个动作,别混为一谈。
小结(也是整门课小结)
这一节跑通了 md-tools 的完整进阶闭环。回顾整门课,你已掌握:
- 上下文与系统提示词:AGENTS.md 深化约定、SYSTEM.md / APPEND_SYSTEM.md 定制、Project Trust 信任机制
- 自定义技能:把
md-tools打包成可复用、可跨 Harness 的 Skill - 提示词模板:用
$1/$@固化常用命令 - 扩展开发:registerTool / registerCommand / 事件系统 / 生命周期
- 贯穿项目:md-tools 从脚本升级为 Skill + Extension 的一等公民
「封装一次、处处复用」——这就是 Pi 进阶的核心回报。用它去打磨属于你自己的工具箱吧。