Superpowers 的 Pi 扩展实现指南:Pi 包清单、会话引导注入机制与 Drill 评估后端
本文以 Superpowers 仓库中 Pi Extension and Evals Implementation Plan 这份实施计划为主体,完整拆解“为 Pi 编程 Agent 提供一等包支持 + 将 Pi 接入 Drill 评估后端”这一需求的设计与落地方式。读完本文,你将理解 Pi 包清单如何声明、.pi/extensions/superpowers.ts 如何在会话启动与压缩(compaction)后注入引导上下文、Pi 工具映射参考文档的约定,以及 Drill 评估框架中 Pi 后端的命令、会话日志过滤与归一化设计。
计划总览:目标、架构与技术栈
该计划是一份典型的“为 Agent 执行者编写”的 TDD 实施计划(文档头部明确要求使用 superpowers:subagent-driven-development 或 superpowers:executing-plans 技能逐任务执行,步骤用 - [ ] 复选框跟踪)。其核心声明为:
- Goal(目标):为 Superpowers 增加一等公民的 Pi 包支持,并将 Pi 加入 Drill 评估(eval)后端。
- Architecture(架构):Pi 包在根目录
package.json中声明,加载现有的skills/目录加一个小型 Pi 扩展。该扩展在会话启动和压缩之后,将using-superpowers引导内容(bootstrap)以 user 角色消息注入 provider 上下文,并附带 Pi 专属的工具映射。Drill 侧则新增pi后端、Pi 会话日志归一化,以及对应测试。 - Tech Stack(技术栈):Pi 的 TypeScript 扩展 API、Node 内置测试运行器(
node:test)、Drill 的 Python 评估框架(pytest)。
计划分为四个任务:任务 1(Pi 包清单与扩展测试)、任务 2(Pi 工具映射参考文档)、任务 3(Drill Pi 后端与会话日志归一化)、任务 4(文档与全量验证)。下面逐任务展开,并结合仓库当前实际代码与测试说明实现细节。
任务 1:Pi 包清单与扩展测试
涉及文件:
- 修改:
package.json - 新建:
tests/pi/test-pi-extension.mjs
1.1 清单(Manifest)字段设计
计划要求更新根目录 package.json,在保留既有 name、version、type、main 字段的前提下,新增 description、keywords、pi.extensions、pi.skills。仓库当前 package.json 的实际内容印证了这一设计:
{
"name": "superpowers",
"version": "6.2.0",
"description": "Superpowers skills and runtime bootstrap for coding agents",
"type": "module",
"main": ".opencode/plugins/superpowers.js",
"keywords": [
"pi-package",
"skills",
"tdd",
"debugging",
"collaboration",
"workflow"
],
"pi": {
"extensions": [
"./.pi/extensions/superpowers.ts"
],
"skills": [
"./skills"
]
}
}
这里有三个值得注意的实现细节:
keywords中的pi-package:这是 Pi 生态识别“可安装包”的约定标记,测试会显式断言它存在。pi.skills: ["./skills"]:直接复用仓库既有技能目录,Pi 拥有原生 skill 系统,因此无需任何兼容层Skill工具——这是计划架构里“no compatibility Skill tool is required”的落点。- 路径演进:计划文本中最初写的是
pi.extensions: ["./extensions/superpowers.ts"],而当前代码是./.pi/extensions/superpowers.ts。从 git 历史(提交chore: keep pi extension under .pi)可以看到扩展最终被移入.pi/目录,使 Pi 专属资源与其他 harness 的插件目录(如.opencode/、.codex-plugin/)保持对称的目录布局。这类“计划路径 vs 落地路径”的偏差在实施计划中很常见,本文后文引用源码时均以当前仓库状态为准。
1.2 扩展实现解析:.pi/extensions/superpowers.ts
计划对扩展的行为规格(Step 4)是:
- 从
import.meta.url定位包根目录; - 读取
skills/using-superpowers/SKILL.md; - 剥离 YAML frontmatter;
- 追加 Pi 专属工具映射;
- 通过
resources_discover暴露 skills 路径; - 在
session_start与session_compact时标记“bootstrap 待注入”; - 在
context钩子中注入 user 角色 bootstrap 消息,且插入位置在开头的compactionSummary消息之后; - 在
agent_end时清除待注入标记; - 不注册
session_before_compact(引导只在压缩“之后”生效,而不是在压缩前塞入上下文)。
当前 .pi/extensions/superpowers.ts 是一个零运行时依赖(仅用 node:fs、node:path、node:url 内置模块)的 TypeScript 文件,逐项实现了上述规格。核心机制如下:
(1)生命周期状态机。 扩展用一个闭包内的布尔标志 injectBootstrap 控制注入开关:
let injectBootstrap = true;
pi.on("session_start", async () => { injectBootstrap = true; });
pi.on("session_compact", async () => { injectBootstrap = true; });
pi.on("agent_end", async () => { injectBootstrap = false; });
即“会话启动”与“发生压缩”都会重新开启注入,“一轮 Agent 执行结束”则关闭。
(2)去重与缓存。 bootstrap 内容通过模块级缓存 cachedBootstrap(三态:undefined 未加载、null 加载失败、字符串成功内容)只读一次文件;每次构造时包含一个固定标记 superpowers:using-superpowers bootstrap for pi(BOOTSTRAP_MARKER)。context 钩子在处理前先检查现有消息中是否已含该标记(messageContainsBootstrap 同时兼容字符串与 content-parts 两种消息形态),存在则直接返回 undefined 表示不修改上下文,从而保证重复的 provider 请求不会注入两份 bootstrap。
(3)压缩摘要之后的插入位置。 这是本扩展最有讲究的一点。压缩发生后,会话头部会出现若干 role: "compactionSummary" 的消息;bootstrap 必须插在这些摘要之后、其余消息之前,这样引导内容在时间线上晚于历史总结、早于用户最新输入:
const insertAt = firstNonCompactionSummaryIndex(event.messages);
return {
messages: [
...event.messages.slice(0, insertAt),
bootstrapMessage,
...event.messages.slice(insertAt),
],
};
其中 firstNonCompactionSummaryIndex 从索引 0 起跳过所有连续的 compactionSummary 消息。
(4)Bootstrap 内容的组装。 getBootstrapContent() 读取 skills/using-superpowers/SKILL.md,用正则 /^---\n[\s\S]*?\n---\n([\s\S]*)$/ 剥掉 frontmatter 后,包裹成如下结构:
<EXTREMELY_IMPORTANT>
superpowers:using-superpowers bootstrap for pi
You have superpowers.
The using-superpowers skill content is included below and is already loaded for this Pi session. Follow it now. Do not try to load using-superpowers again.
{SKILL.md 正文}
## Pi tool mapping
{内联的 Pi 工具映射文本}
</EXTREMELY_IMPORTANT>
值得注意的一个设计区分是:扩展内联了一份工具映射文本(piToolMapping() 函数,见 superpowers.ts 第 88–98 行),而不是在运行时读取任务 2 的参考文档。参考文档 pi-tools.md 是给 Agent 按需查阅的“规范文档”,内联文本是保证每轮上下文都携带的“硬约束”,两者内容互为镜像。
内联映射的核心内容与 skills/using-superpowers/references/pi-tools.md 一致:Pi 有原生 skills 但没有 Claude Code 的 Skill 工具;内建编码工具是小写的 read、write、edit、bash,外加可选的 grep、find、ls;Pi 核心不带标准子代理(subagent)工具,若安装了 pi-subagents 提供 subagent 工具则使用它,否则不要虚构 Task 调用;Pi 核心也不带标准任务列表工具,旧的 TodoWrite 应视为“任务跟踪动作”,可用计划文件或仓库本地 TODO.md 跟踪。
(5)资源发现。 resources_discover 钩子返回 skillPaths: [skillsDir],把整个 skills/ 目录贡献给 Pi 的资源系统。
1.3 测试实现:tests/pi/test-pi-extension.mjs
计划 Step 1 要求先写“失败测试”:导入扩展、注册一组假的 Pi handler、断言清单与行为。当前 tests/pi/test-pi-extension.mjs 的写法是:
- 构造一个假的
pi对象,其on(event, handler)把 handler 存入Map<event, handler[]>; - 通过
import(pathToFileURL(extensionPath).href + '?cachebust=...')动态导入.pi/extensions/superpowers.ts,调用默认导出完成注册; node --experimental-strip-types让 Node 直接执行 TS 扩展文件,无需编译步骤。
六组测试分别锁定计划的每一条断言:
- 清单断言:
name === 'superpowers'、keywords含pi-package、pi.skills深等于['./skills']、pi.extensions深等于['./.pi/extensions/superpowers.ts']; - 生命周期断言:
resources_discover、session_start、session_compact、context、agent_end各恰好注册 1 个 handler,且session_before_compact注册数为 0; - 资源发现断言:
resources_discover返回的skillPaths恰为仓库skills/的绝对路径; - 启动注入断言:
session_start后调用context,结果首条消息为 user 角色、文本匹配/You have superpowers/与/Pi tool mapping/,原用户消息原样保留;重复请求不重复注入;bootstrap 已在消息中时返回undefined;agent_end之后待注入被清除; - 压缩注入断言:
session_compact后,context将 bootstrap 插入到compactionSummary消息之后、用户消息之前(结果消息数为 3,顺序为 summary → bootstrap → user); - 参考文档断言:
pi-tools.md存在,且仅对映射表格行(|开头的行)断言包含 subagent 与 todo/task 条目——测试注释明确说明这是为了防止“删掉表格只留下正文描述”造成的假通过。
运行方式(计划中 RED/GREEN 两步均使用同一条命令):
node --experimental-strip-types --test tests/pi/test-pi-extension.mjs
预期在实现前 FAIL(扩展与 pi 清单不存在),实现后 PASS。
任务 2:Pi 工具映射参考文档
涉及文件:
- 新建:
skills/using-superpowers/references/pi-tools.md - 修改:
tests/pi/test-pi-extension.mjs
计划的规格是:文档需覆盖 Skill、Task、TodoWrite 与内建工具名的映射,并说明 Pi 的原生 skills、可选的 pi-subagents、以及“没有标准 todo/tasklist 插件”的事实。当前 skills/using-superpowers/references/pi-tools.md 的内容结构如下(此处完整给出):
- 开头点明定位:技能以“动作”表述(“dispatch a subagent”“create a todo”“read a file”),在 Pi 上解析为下表的工具;
- 映射表:
| 技能请求的动作 | Pi 等价物 |
|---|---|
派发子代理(Subagent (general-purpose): 模板) |
若可用,使用已安装子代理工具,如 pi-subagents 提供的 subagent |
| 任务跟踪(“create a todo”“mark complete”) | 若可用,使用已安装的 todo/task 工具,否则在计划或 TODO.md 中跟踪任务 |
- Subagents 一节:Pi 核心不附带标准子代理工具;
pi-subagents是强推荐的可选伴侣包,提供带单代理、链式、并行、异步、forked-context、resume/status 工作流的subagent工具;若无子代理工具,不要虚构Task调用,应在当前会话顺序执行或向用户说明该可选能力未安装。 - Task lists 一节:Pi 核心不附带标准任务列表工具;若安装了 todo/task 扩展则用其文档工具,否则用 Superpowers 计划文件、Markdown 复选框或仓库本地
TODO.md;旧版 Superpowers 文档中的TodoWrite应视为上表的任务跟踪动作。
测试侧(任务 1 的第 6 组断言)对这份文档做了防退化校验:只解析表格行,要求至少一行匹配 /subagent/i、至少一行匹配 /todo|task/i。这体现了计划“用测试钉住文档契约”的一贯思路——参考文档不是散文,而是有可测试形态的规范。
任务 3:Drill Pi 评估后端与会话日志归一化
涉及文件:
- 新建:
evals/backends/pi.yaml - 修改:
evals/drill/backend.py、evals/drill/engine.py、evals/drill/normalizer.py - 修改:
evals/tests/test_backend.py、evals/tests/test_normalizer.py
这一任务把 Pi 接入 Drill 评估框架。计划给出的测试规格(Step 1)明确了五个可验证点:
load_backend("pi")返回family == "pi";- Pi 后端的启动命令以
pi开头,且包含-e ${SUPERPOWERS_ROOT}; _resolve_log_dir()对 Pi 指向~/.pi/agent/sessions;filter_pi_logs_by_cwd()只保留头部cwd与场景工作目录一致的会话文件;normalize_pi_logs()从 Pi 助手(assistant)会话条目中提取toolCall块,并把小写内建工具名映射为规范(canonical)工具名。
据此,后端配置 evals/backends/pi.yaml 的设计是:
- 命令:
pi -e ${SUPERPOWERS_ROOT}——与 README 中“本地开发时以临时包方式加载本检出”的用法(pi -e /path/to/superpowers)同源,-e参数把 Superpowers 仓库作为临时扩展包挂载进 Pi; - 就绪判定:宽松(permissive)的 TUI readiness 策略,容忍 TUI 界面启动时序;
- 关停:发送
/quit退出 Pi 会话; - 日志位置:Pi 会话日志目录(
~/.pi/agent/sessions)。
引擎与归一化层的实现规格(Step 4):
Backend.family增加"pi"家族;Engine._resolve_log_dir针对 Pi 返回~/.pi/agent/sessions;Engine._collect_tool_calls适配 Pi 的日志形态;normalizer.py实现两个 Pi 专属函数:filter_pi_logs_by_cwd(按会话头部的cwd字段过滤,保证评估场景只采集自己工作目录的会话)与normalize_pi_logs(解析 assistant 条目中的toolCall块,把read/write/edit/bash等小写内建工具名归一为 Drill 统一的规范名,供后续断言使用)。
对应测试用 pytest 运行:
uv run pytest evals/tests/test_backend.py evals/tests/test_normalizer.py -q
需要说明当前仓库状态的一个事实:evals/ 目录不在当前仓库快照中。从 git 历史可以确认,评估框架曾通过提交 Move eval harness to submodule (#1541) 移出主仓库成为独立子模块,Pi 后端相关工作以 Bump evals submodule for Pi backend 的提交形式在子模块中推进,后续版本(v6.0.2 起)不再随主仓库分发 evals 子模块。因此本文对任务 3 的描述以本计划文档为设计权威,evals/ 下的具体文件请以其所在评估仓库的实际检出为准。
任务 4:文档与全量验证
涉及文件:
- 修改:
README.md - 修改:
evals/README.md
计划要求在 README 的快速开始/安装列表中登记 Pi,并在 evals/README.md 中补充后端条目与用法。当前 README.md 的 “Pi” 小节(约第 180–194 行)完整落地了这一要求:
# 作为 Pi 包安装
pi install git:github.com/obra/superpowers
# 本地开发:把本检出作为临时包加载
pi -e /path/to/superpowers
并说明:Pi 包加载 Superpowers 技能与一个小型扩展,在会话启动及压缩后注入 using-superpowers bootstrap;由于 Pi 有原生 skills,不需要兼容 Skill 工具;子代理与任务列表工具仍是可选的 Pi 伴侣包。RELEASE-NOTES.md 也以 “Pi — a session-start extension that registers the skills and injects the using-superpowers bootstrap. Pi has native skills, so it needs no compatibility shim.” 概括了该能力。
最后一步是全量验证,计划给出的命令为:
node --experimental-strip-types --test tests/pi/test-pi-extension.mjs
uv run pytest evals/tests/test_backend.py evals/tests/test_setup.py evals/tests/test_normalizer.py -q
预期所有测试通过。
关键设计点回顾
回到计划的整体脉络,这份实施计划体现了 Superpowers 多 harness 适配的三条工程原则:
- 清单即适配:Pi 的一等支持本质上就是
package.json里keywords、pi.skills、pi.extensions三组声明加一个约 120 行的零依赖 TS 扩展,复用既有skills/内容,不复制、不分叉; - 引导注入的时序正确性:bootstrap 只在“会话启动后”和“压缩后”注入(注册
session_start/session_compact而不注册session_before_compact),插入位置在所有compactionSummary之后,并用内容标记去重——保证 Agent 每轮都能“记得自己有 superpowers”,但绝不在压缩前污染待压缩上下文; - 文档与测试同契约:
pi-tools.md这类参考文档不是普通说明,其映射表被测试按行钉住;扩展行为则被一组“假pi.on注册表 + 事件序列重放”的测试完整锁定,任何行为回归都会让node --test失败。
对于维护该项目的 Agent 或开发者,建议的阅读与验证路径是:先读本计划了解任务拆分与验收标准,再对照 package.json、.pi/extensions/superpowers.ts、tests/pi/test-pi-extension.mjs、skills/using-superpowers/references/pi-tools.md 与 README.md 的 Pi 小节核对落地细节,最后运行任务 4 中的验证命令确认全绿。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0626
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00