Pi Agent 命令与快捷键注册
通过扩展注册自定义命令、键盘快捷键和 CLI 标志,让 Pi Agent 更好地适应你的工作流。
注册自定义命令
使用 pi.registerCommand() 注册用户可通过 / 调用的命令:
实例
// 基础命令
pi.registerCommand("stats", {
description: "显示当前会话的统计信息",
handler: async (args, ctx) => {
const count = ctx.sessionManager.getEntries().length;
ctx.ui.notify(`共 ${count} 条消息`, "info");
}
});
// 带参数自动补全的命令
pi.registerCommand("deploy", {
description: "部署到指定环境",
// 定义参数自动补全
getArgumentCompletions: (prefix) => {
const envs = ["dev", "staging", "prod"];
const items = envs
.filter(e => e.startsWith(prefix))
.map(e => ({ value: e, label: e }));
return items.length > 0 ? items : null;
},
handler: async (args, ctx) => {
if (!args) {
ctx.ui.notify("用法: /deploy <环境名>", "warning");
return;
}
ctx.ui.notify(`正在部署到 ${args} 环境...`, "info");
},
});
pi.registerCommand("stats", {
description: "显示当前会话的统计信息",
handler: async (args, ctx) => {
const count = ctx.sessionManager.getEntries().length;
ctx.ui.notify(`共 ${count} 条消息`, "info");
}
});
// 带参数自动补全的命令
pi.registerCommand("deploy", {
description: "部署到指定环境",
// 定义参数自动补全
getArgumentCompletions: (prefix) => {
const envs = ["dev", "staging", "prod"];
const items = envs
.filter(e => e.startsWith(prefix))
.map(e => ({ value: e, label: e }));
return items.length > 0 ? items : null;
},
handler: async (args, ctx) => {
if (!args) {
ctx.ui.notify("用法: /deploy <环境名>", "warning");
return;
}
ctx.ui.notify(`正在部署到 ${args} 环境...`, "info");
},
});
如果多个扩展注册了同名的命令,Pi Agent 会保留所有注册并按加载顺序添加数字后缀,例如 /review:1 和 /review:2。这避免了扩展之间的命名冲突。
命令上下文 (ExtensionCommandContext)
命令的 handler 接收的是 ExtensionCommandContext,它继承自 ExtensionContext,并额外提供以下方法:
| 方法 | 说明 |
|---|---|
| ctx.waitForIdle() | 等待 AI 完全空闲(包括重试、压缩、跟进消息全部完成) |
| ctx.newSession(options) | 创建新会话,可指定父会话和初始化逻辑 |
| ctx.fork(entryId, options) | 从指定条目分叉出新会话 |
| ctx.navigateTree(targetId, options) | 导航到会话树中的指定位置 |
| ctx.switchSession(sessionPath, options) | 切换到另一个会话文件 |
| ctx.reload() | 执行与 /reload 相同的热重载流程 |
会话切换命令示例:
实例
import { SessionManager } from "@earendil-works/pi-coding-agent";
pi.registerCommand("switch", {
description: "切换到另一个会话",
handler: async (args, ctx) => {
// 列出当前项目的所有会话
const sessions = await SessionManager.list(ctx.cwd);
if (sessions.length === 0) {
ctx.ui.notify("没有可用的会话", "warning");
return;
}
// 弹出选择列表
const choice = await ctx.ui.select(
"选择要切换的会话:",
sessions.map(s => s.file),
);
if (choice) {
// 切换到选中的会话
await ctx.switchSession(choice, {
withSession: async (ctx) => {
ctx.ui.notify("已切换会话", "info");
},
});
}
},
});
pi.registerCommand("switch", {
description: "切换到另一个会话",
handler: async (args, ctx) => {
// 列出当前项目的所有会话
const sessions = await SessionManager.list(ctx.cwd);
if (sessions.length === 0) {
ctx.ui.notify("没有可用的会话", "warning");
return;
}
// 弹出选择列表
const choice = await ctx.ui.select(
"选择要切换的会话:",
sessions.map(s => s.file),
);
if (choice) {
// 切换到选中的会话
await ctx.switchSession(choice, {
withSession: async (ctx) => {
ctx.ui.notify("已切换会话", "info");
},
});
}
},
});
会话替换的注意事项:withSession 回调中的 ctx 是一个全新的上下文。不要使用旧的 pi 对象或命令回调中捕获的 ctx,它们在会话替换后会变成无效状态。
注册快捷键
使用 pi.registerShortcut() 注册自定义键盘快捷键:
实例
pi.registerShortcut("ctrl+shift+p", {
description: "切换 Plan 模式",
handler: async (ctx) => {
ctx.ui.notify("已切换 Plan 模式!", "info");
},
});
description: "切换 Plan 模式",
handler: async (ctx) => {
ctx.ui.notify("已切换 Plan 模式!", "info");
},
});
快捷键格式为 修饰键+按键,例如 ctrl+shift+p、alt+x 等。
注册 CLI 标志
使用 pi.registerFlag() 为 pi 命令添加自定义 CLI 参数:
实例
pi.registerFlag("plan", {
description: "以 Plan 模式启动",
type: "boolean",
default: false,
});
// 在扩展代码中检查标志值
if (pi.getFlag("plan")) {
// Plan 模式已启用
pi.on("before_agent_start", async (event, ctx) => {
return {
systemPrompt: event.systemPrompt
+ "\n\nPlan Mode:先提出计划,经用户确认后再执行。",
};
});
}
description: "以 Plan 模式启动",
type: "boolean",
default: false,
});
// 在扩展代码中检查标志值
if (pi.getFlag("plan")) {
// Plan 模式已启用
pi.on("before_agent_start", async (event, ctx) => {
return {
systemPrompt: event.systemPrompt
+ "\n\nPlan Mode:先提出计划,经用户确认后再执行。",
};
});
}
使用方式:
$ pi --plan "帮我实现用户认证功能"
扩展间通信
使用 pi.events 在扩展之间共享事件:
实例
// 扩展 A:发送事件
pi.events.emit("deploy:completed", {
env: "production",
timestamp: Date.now(),
});
// 扩展 B:监听事件
pi.events.on("deploy:completed", (data) => {
console.log(`部署完成:${data.env}`);
});
pi.events.emit("deploy:completed", {
env: "production",
timestamp: Date.now(),
});
// 扩展 B:监听事件
pi.events.on("deploy:completed", (data) => {
console.log(`部署完成:${data.env}`);
});
获取已注册的命令
使用 pi.getCommands() 获取当前会话中所有可用的命令:
实例
const commands = pi.getCommands();
// 按来源分类
const extCommands = commands.filter(
c => c.source === "extension"
);
const templates = commands.filter(
c => c.source === "prompt"
);
const skills = commands.filter(
c => c.source === "skill"
);
// 按来源分类
const extCommands = commands.filter(
c => c.source === "extension"
);
const templates = commands.filter(
c => c.source === "prompt"
);
const skills = commands.filter(
c => c.source === "skill"
);
每个命令条目包含 name(命令名)、description(描述)、source(来源类型)和 sourceInfo(详细的来源元数据)。
动态工具管理
运行时管理工具的启用和禁用:
实例
// 获取当前启用的工具列表
const active = pi.getActiveTools();
// 例如:["read", "bash", "edit", "write"]
// 获取所有已注册工具的元数据
const all = pi.getAllTools();
// 筛选内置工具
const builtinTools = all.filter(
t => t.sourceInfo.source === "builtin"
);
// 筛选扩展注册的工具
const extTools = all.filter(
t => t.sourceInfo.source !== "builtin"
&& t.sourceInfo.source !== "sdk"
);
// 动态启用自定义工具(保留现有工具)
pi.setActiveTools([...new Set([...active, "my_tool"])]);
// 切换到只读模式
pi.setActiveTools(["read", "bash"]);
const active = pi.getActiveTools();
// 例如:["read", "bash", "edit", "write"]
// 获取所有已注册工具的元数据
const all = pi.getAllTools();
// 筛选内置工具
const builtinTools = all.filter(
t => t.sourceInfo.source === "builtin"
);
// 筛选扩展注册的工具
const extTools = all.filter(
t => t.sourceInfo.source !== "builtin"
&& t.sourceInfo.source !== "sdk"
);
// 动态启用自定义工具(保留现有工具)
pi.setActiveTools([...new Set([...active, "my_tool"])]);
// 切换到只读模式
pi.setActiveTools(["read", "bash"]);
