Files
my-pi/README.md
T
云服务部-叶林立andDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> 833b9514d4 feat(update): update.sh 先同步 Pi 最新 release 再升级组合包
pi update <source> 只更新单个包,Pi 本体不会随之升级;改为先执行
pi update --self(版本比较由 Pi 自身完成,已是最新时跳过,失败记录后继续),
再升级组合包。

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-21 23:26:43 -07:00

395 lines
41 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# my-pi
个人维护的 Pi 扩展组合包。安装一次即可加载并配置:
- `@ff-labs/pi-fff@0.10.5`:使用官方 `override` 模式接管 `find`、`grep` 和 `multi_grep`。
- 本仓库维护的 `pi-rtk-optimizer`:只处理 Bash/read 等输出压缩,默认不改写命令,也不处理搜索工具结果。
- 本仓库自维护的 `pi-web-search`:对模型只暴露 `web_search` / `web_fetch` 两个工具;`web_search` 由当前主模型在 Tavily / Exa / Keenable 间路由,`web_fetch` 固定走 Exa,三家均以纯 `fetch` 直连(Exa 为 `mcp.exa.ai` 的 JSON-RPC,不经 MCP adapter)。
- `extensions/codegraph.ts`:注册原生 `codegraph_explore` 工具,按索引根惰性启动常驻 `codegraph serve --mcp` 子进程,由组合包自有 stdio JSON-RPC 客户端直连(无 MCP adapter/SDK);serve 的文件监听自动同步索引,无结果缓存;未初始化项目经确认后才 `codegraph init`,拒绝记入会话不再重复询问。
- `extensions/context-view.ts`:通过 `/context` 只读显示 `pi-compaction` 的 effective context,不建立第二套上下文口径。
- `pi-lsp@0.1.7`:为 TypeScript/JavaScript、Kotlin 和 Java 提供 LSP 诊断、跳转与符号工具;TypeScript 后端由组合包内置。
- `pi-hermes-memory/`:从官方 `pi-hermes-memory v0.9.10` 源码导入的持久记忆扩展,提供全局/项目/用户/失败四类记忆、SQLite FTS5 会话与记忆检索、`SKILL.md` 过程记忆、correction 检测与自动 consolidation。
- 本仓库维护的 `pi-minimal-footer`:基于 `@ogulcancelik/pi-minimal-footer@0.1.10`,用紧凑的上下文仪表和订阅用量条替换默认 footer。
- 本仓库维护的 `pi-notify`:基于 `@smoose/pi-notify@0.1.1`,使用 Kitty OSC 99 在 Pi 完全 settled 或权限系统即将请求人工确认时通知,并支持点击精确聚焦来源 Kitty 窗口。
- 本仓库维护的 `pi-compaction`:压力触发时以 Pi `context_edit` 批量遮蔽旧工具结果、空闲时按阈值触发整段摘要、effective token 计量、`context_tree_query`、portable checkpoint 与 Codex native compaction。
- 本仓库自维护的 `pi-overflow`:统一的新工具结果展示截断——超阈值原文落盘、向模型展示「头 + 信号行 + 尾」的有界视图,并提供 `overflow_query` 按 id 搜索、行区间或 JSON 路径取回原文。
- 本仓库维护的 `pi-ask-user`:提供模型主动调用的 `ask_user_question`;TUI 中保留单题、多题、选择、文本、自定义回答与提交前复核,Paseo 等兼容 RPC 客户端通过标准 Pi extension UI 逐题交互。
- 本仓库自维护的 `pi-worktree`:纯斜杠命令(`/wt` / `/worktree`)git worktree 管理,`/wt new` 一键拆分、`/wt merge` 一键合并回来源分支(默认 ff-only,可选 `--squash`),通过 `SessionManager.forkFrom` + `switchSession` 切换会话 cwd;登记状态在 `<agentDir>/pi-worktree/state.json`,不注册模型工具、不 push。
- 本仓库维护的 `pi-tool-search`:从完整工具定义生成并缓存经过校验的工作流分组,默认以最多 5 个动态组、28 个动态工具的 LRU 策略加载原始完整 schema,并支持原子批量激活。
- 本仓库维护的 `pi-chrome`:从上游 `0.15.46` 源码导入,通过显式会话授权接入用户当前已登录的 Chrome Profile;页面快照 JSON 直接作为工具结果返回,超长时由 pi-overflow 截断并用 `overflow_query` 查询,21 个 `chrome_*` 工具仍由 Tool Search 按工作流加载。
- 本仓库维护的 `pi-permission-system`:只读取一份全局普通策略与一份独立 Hard Guards,按 pattern 具体度裁决 allow/ask/deny,并整合 Codex Guardian 风格 AutoReview 与人工 `defer` 兜底;自动评审模型完全由配置文件指定,未配置时提示并转人工审批;工具显隐仍只由 Tool Search 管理。
- 本仓库维护的 `pi-subagents`:从 `@tintinweb/pi-subagents@0.18.0` 源码导入并默认加载,提供隔离子 Agent、后台执行、steering、resume、嵌套代理与自定义 Agent;通过 mandatory permission wrapper 接入权限 child lifecycle、根 authority `ask` 转发和根 transcript auto-review 身份桥接,其 3 个编排工具由 Tool Search 的 `subagents` 组按需加载。子 Agent 使用独立提示词画像 `config/prompt/subagent/`(自有 preamble 与内置 Agent 定义),不嵌入父会话提示词。
- 本仓库维护的 `pi-ssh`:通过纯 Node `ssh2` 持久连接、显式 `ssh_cd` 远端工作区切换、SFTP 与自适应有界搜索提供独立的远端工具;Agent 只在用户明确指定已导入主机及具体任务后发起受 AutoReview 复核的连接。
- `extensions/system-prompt.ts`:组合包唯一的系统提示词出口(排在最后加载),按 `config/prompt/` 组合开场白、工具简介与跨工具路由规则;提供 `/dump-system-prompt` 导出当前有效提示词。
## 安装、升级与卸载
推荐从仓库检出目录运行安装脚本:
```bash
./install.sh
```
脚本会先执行:
```bash
pi install git:git@bitbucket.org:siakitem/my-pi.git
```
安装组合包成功后,脚本会依次检查终端环境和机器级 CLI。所有缺失项目都逐项显示
`[y/N]`,默认拒绝,仅在用户明确选择 `Y` 后修改机器或用户配置:
- 检查 Kitty;macOS 使用 Homebrew cask 安装,其他系统使用 Kitty 官方安装器。Kitty
可用后继续检查并可通过官方 `themes` kitten 配置 `Solarized Dark`。
- 检查 Oh My Zsh。安装采用官方 unattended 模式,不切换默认 shell、不立即启动 Zsh,
也不覆盖现有 `.zshrc`。
- 检查 Powerlevel10k;可克隆到 Oh My Zsh 的 custom themes 目录,并把仓库内置的
`config/p10k.zsh` 原子同步到 `~/.config/my-pi/p10k.zsh`(遵循 `XDG_CONFIG_HOME`)。
该配置来自当前使用的 Powerlevel10k Rainbow/ASCII 单行紧凑主题;用户自己的
`~/.p10k.zsh` 不会被覆盖。脚本只在 `.zshrc` 中写入带首尾标记的主题和加载受管块。
- 逐项检查 `git`、`zsh-autosuggestions` 和 `zsh-syntax-highlighting` 是否已经在
`.zshrc` 的 `plugins` 数组中启用。后两个插件缺少源码时会先克隆到 Oh My Zsh 的
custom plugins 目录;语法高亮按最后一个插件处理。
- 最后继续检查 `codegraph`、`kotlin-lsp`、Java 21+ 和 `jdtls`。Kotlin、Java 和 JDT LS
的自动安装使用 Homebrew,CodeGraph 使用官方安装脚本。
脚本首次实际改动 `.zshrc` 前会在同目录创建带时间戳的备份。Oh My Zsh loader、
Powerlevel10k 主题/配置和各 Zsh 插件使用 `# >>> my-pi:<id> >>>` 到
`# <<< my-pi:<id> <<<` 的受管块协议;以后只替换块内内容,块外用户配置保持不变。
标记缺失、重复或不完整时脚本会拒绝修改。若机器没有所需的 Homebrew、`curl` 或 `git`,
脚本会保留已完成的安装结果、继续检查其他项目,并最终返回非零状态。
`rtk` 只供默认关闭的命令改写使用,因此不会作为必装依赖检查。
也可以绕过脚本,直接运行上面的 `pi install` 命令,此时机器级 CLI 不会被检查。
升级已安装的组合包请使用独立脚本:
```bash
./update.sh
```
升级脚本先把 Pi 本体同步到最新发布版本,再升级组合包:
```bash
pi update --self
pi update git:git@bitbucket.org:siakitem/my-pi.git
```
`pi update --self` 由 Pi 自己比较本地与最新 release,已是最新时直接跳过;它失败只记录为升级失败,不阻断组合包升级。脚本不会在升级前破坏性预清理安装缓存:组合包的 `pi update` 失败时立即停止后续升级——Pi 1.3.0 会在下一次 `pi update` 时依据自己的 `.pi-update-incomplete` 标记自动重新清理并恢复未完成的升级,重新运行 `update.sh` 即可,脚本不做人工恢复。
随后只处理已经安装的项目,未安装项直接跳过且不会询问安装:Kitty 及已启用的
Solarized Dark、Oh My Zsh、Powerlevel10k、两个第三方 Zsh 插件、CodeGraph,以及由
Homebrew 管理的 Kotlin LSP、Java 21 和 JDT LS。升级前会先刷新或查询对应的远端版本:
Git checkout 在 `fetch` 后比较本地与上游提交,Homebrew 包在刷新元数据后通过 `brew outdated`
判断,Kitty 官方安装和 CodeGraph 则比较本地版本与官方最新发布版本。只有检测到版本不同时才
下载并替换;无法确认安装来源或无法可靠比较版本时保留现状并报告。
日志中的“Zsh 插件未安装,升级流程跳过”不是升级失败:升级脚本不会新增用户此前未选择的
插件。需要补装时重新运行 `./install.sh`,并在对应的逐项询问中明确选择 `Y`。
`pi update` 在有新版本时用更新后的组合包整体覆盖已安装副本;`update.sh` 在每次成功升级后还会把默认 git 来源的已安装 checkout `git reset --hard` 还原到已发布版本(本地路径来源不 reset,不做 `git clean` 以保留 `node_modules`),因此对已安装副本(含 `config/`)的本地修改不会保留。扩展运行时直接读取已安装组合包内的 `config/` 文件,脚本不再做任何配置部署。Powerlevel10k 受管副本只在内容不同时备份并原子同步;`.zshrc` 也只更新已有的 my-pi 受管块,不触碰块外配置。因此安装流程负责补齐缺失项,升级流程只升级已安装项。
卸载组合包:
```bash
./uninstall.sh
```
卸载脚本只调用 `pi remove`,不会删除 Kitty、终端主题、Oh My Zsh、Powerlevel10k、Zsh
插件、CodeGraph、Kotlin LSP、JDT LS 或 Java,因为这些用户环境或机器级工具可能仍被其他
项目使用。三个脚本都可通过 `PI_PACKAGE_SOURCE` 覆盖默认包源,
例如在本地检出中测试:
```bash
PI_PACKAGE_SOURCE="$PWD" ./install.sh
PI_PACKAGE_SOURCE="git:git@bitbucket.org:siakitem/my-pi.git" ./update.sh
```
根 `package.json` 对外部依赖使用精确版本,对本仓库维护的包使用 `file:` 路径;`package-lock.json` 固定完整依赖树。不要再用项目级 `.pi/settings.json` 重复安装这些扩展,否则同一扩展可能被加载两次。
持久记忆由本仓库维护的 `pi-hermes-memory` 提供。它从官方 `chandra447/pi-hermes-memory`
的 `v0.9.10` / `df624056a2e8c68bc89ba0a81e1c120856ec9665` 导入源码到 `pi-hermes-memory/` 并直接加载,
通过本地 `file:` 依赖安装,不需要额外的机器级 CLI。
默认 `policy-only` 模式只把 `<memory-policy>` 指令注入 system prompt,不注入记忆正文,因此不会改变
prompt 前缀、对前缀缓存友好。模型需要历史上下文时主动调用 `memory_search` / `session_search`,
写入用 `memory_add` / `memory_replace` / `memory_remove`,过程记忆用 `skill_manage`。这六个工具由
Tool Search 常驻,保证 policy 指示与模型可见工具一致。
记忆与 skill 数据位于 `~/.pi/agent/pi-hermes-memory/`(全局)与 `~/.pi/agent/projects-memory/<项目>/`
(项目级)。这些是用户数据,安装、升级与卸载脚本不会创建、迁移或删除;扩展配置来自已安装组合包的
`config/pi-hermes-memory.json`。
CodeGraph 采用惰性初始化:`codegraph_explore` 在未建立索引的项目上被调用时会先向用户确认,
确认后才运行 `codegraph init` 并自动重试本次探索,拒绝一次后本会话不再询问;不需要手动执行任何初始化命令。
默认配置不需要系统 `rtk` CLI。只有以后在 `/rtk` 中主动开启 RTK command rewriting 时,才需要另外安装 `rtk` 可执行文件。
CodeGraph 本体不由组合包安装。需要使用 CodeGraph 的机器应自行确保 `codegraph` 在
启动 Pi 的 `PATH` 中(`install.sh` 会交互式提供官方安装)。扩展只有在用户于确认对话框中
明确同意后才会创建 `.codegraph/`;安装、升级和普通启动流程不会创建或维护索引,也不会修改
CodeGraph 的更新或遥测设置。
## 组合行为
### 模型主动提问
`pi-ask-user/` 把 Pi 上游的单题与多题示例合并为唯一的 `ask_user_question` 工具;不提供 `/qna` 或其他用户命令。模型只有在继续任务确实缺少用户决定、偏好、确认或澄清时才应加载 `user-interaction` 组并调用它,不得重复询问直接消息中已有的信息。工具最多一次提交 8 个问题:交互式 TUI 支持选择、自由文本、显式跳过、返回修改和最终复核;Paseo 等具备 Pi extension UI bridge 的 RPC 客户端使用逐题 `select` / `input` 对话框。取消结果不会作为 AutoReview 的授权证据,JSON/print 等无交互 UI 模式保持拒绝执行。
### 工具与搜索路由
`config/prompt/routing.jsonc` 定义跨工具路由规则,由 `extensions/system-prompt.ts` 在每轮开始前按当前激活工具渲染为 `<tool_routing>` 分区。代码结构、调用关系和待修改 symbol 优先使用 CodeGraph,定义、引用、类型和修改后诊断优先使用 LSP;仓库字面搜索先用 FFF `find` 缩小文件或目录范围,再在已收敛的路径中用 `grep`/`multi_grep` 获取行号。宽泛搜索命中大量结果、发生截断或达到上限时,应继续缩小路径、glob 或 pattern,而不是提高 limit 或输出全部结果。
在线搜索默认按任务只选一个服务:关键词不确定、新闻/近期话题或需要较多候选来源时优先 Tavily;官方/API 文档、版本信息、论文和高确定性事实确认优先 Exa;中文政策、政府公告、中文网页、站点限定和日期筛选优先 Keenable。只有来源质量或不确定性确实需要时才跨服务复核,避免默认把三套结果全部塞进上下文。
日志、测试/构建输出以及不可预测的大输出由 pi-overflow 截断展示,原文可用 `overflow_query` 按 id 检索。只有确实需要精确源码或准备修改时,才用带 `offset/limit` 的 Hashline `read` 读取最小区域并取得 `LINE#HASH` 锚点,随后用锚定 `edit` 修改;成功编辑返回的新锚点可继续复用,只有锚点过期或下一目标区域尚未展示时才重新读取。已有工具结果足够时停止检索,避免对同一问题依次重复调用 CodeGraph、FFF 和 `read`。
使用 `/dump-system-prompt` 可将当前扩展所见的有效提示词写入当前项目的 `.pi-debug/effective-system-prompt.md`。`.pi-debug/` 属于本地诊断输出,默认不提交。
### 系统提示词单一入口
`extensions/system-prompt.ts` 是组合包唯一的系统提示词出口,排在 `pi.extensions` 最后加载。提示词内容全部由 `config/prompt/` 管理:`preamble.md` 替换 Pi 默认开场白(其余 `<tools>`、`<rules>`、`<skills>`、`<project_context>`、`<cwd>` 等分区及顺序原样保留),`tools.jsonc` 覆盖各工具的简介与规则,`routing.jsonc` 渲染 `<tool_routing>` 分区,`sections.jsonc` 决定各扩展贡献分区的顺序。
其他扩展不直接改写提示词:pi-chrome、pi-ssh、pi-hermes-memory 等通过 `systemPromptOptions.sections.<name>` 贡献结构化分区,pi-rtk-optimizer 通过 `promptGuidelines` 补充规则;第三方扩展(FFF、Hashline、LSP)经 `extensions/` 下的包装文件与 `prompt-guard.ts` 代理加载,拦截直接的提示词改写并按 `tools.jsonc` 应用工具说明覆盖。
`config/prompt/` 每轮重新读取(按 mtime 缓存),修改已安装组合包内的文件后下一轮即生效;配置解析失败时警告一次并保持 Pi 默认提示词,不阻止会话。该目录由组合包直接维护并随组合包发布;对已安装副本的本地修改不做保护,`pi update` 会直接覆盖;要长期自定义请直接编辑仓库中的 `config/prompt/`。
### 接管当前 Chrome
组合包固定加载 `pi-chrome@0.15.46`,但不会自动取得浏览器控制权。首次安装后在 Pi 中运行 `/chrome onboard`,按提示在 `chrome://extensions` 以 Developer mode 加载组合包内的 unpacked Chrome 扩展,再执行 `/reload` 与 `/chrome doctor`。每个 Pi session 仍需由用户显式运行 `/chrome authorize`;可用 `/chrome revoke` 立即撤销。Bridge 只监听 `127.0.0.1:17318`,Chrome 扩展具有广泛的 tabs/scripting/debugger 权限,应只从可信组合包安装。
授权后注册的 21 个 `chrome_*` 工具不会常驻提示词;Tool Search 将它们分为 `chrome-navigation`、`chrome-interaction` 和 `chrome-debugging`。普通网页资料发现仍使用 Tavily/Exa/Keenable,只有需要读取登录态页面或实际操作当前 Chrome 时才加载 Chrome 组。
`chrome_snapshot` 和带 `includeSnapshot=true` 的交互把页面快照 JSON 直接作为工具结果返回,`details` 只保留元素数、匹配数等小型元数据;`chrome_find` 只返回紧凑的排序匹配。快照超长时结果会带 `[pi-overflow id=…]` 标记,模型用 `overflow_query` 的 `jsonPath`(如 `elements[0].uid`)或 `search` 提取所需的 uid、文本或状态,而不是重复抓取快照。页面交互后旧快照即失效,需要重新抓取;早期版本写入 Session 临时文件的快照机制已移除。
### 按需加载工具 schema
`pi-tool-search/` 从上游 <https://github.com/tuansondinh/pi-tool-search> 的 `v0.3.6`、commit `ddfb23646fd3957b791214de278e23aa393c9b13` 导入,并像 `pi-rtk-optimizer/` 一样由本仓库直接维护;它不是 submodule,不加载 npm 预编译入口,也不保留嵌套 `.git`、上游 `.pi` 状态或构建产物。来源、许可证说明和本地差异记录在 `pi-tool-search/UPSTREAM.md`。
本地源码直接使用 `@earendil-works/pi-coding-agent`、当前 `typebox`、`ModelRegistry.complete()` 与 `setActiveTools()`,不安装、别名映射或加载旧 `@mariozechner` runtime,也不使用 provider payload 改写、代理执行或隐藏 `sendMessage` 循环。
新 session 默认常驻 Pi 核心 `read`、`write`、`edit`、`bash`、`grep`、`find`,以及 `codegraph_explore`、`lsp_diagnostics`、六个记忆工具、`context_tree_query`、`overflow_query`、Pi 内置 `codemode`(exposure `model-only`)和 `tool_search`;Windows 上额外把内置 `powershell` 与 `bash` 作为同类本地 Shell 核心工具固定启用,非 Windows 平台则从目录中过滤它。exposure 为 `hidden` 或 `codemode`(script-only)的工具一律不进入目录。`codemode` 在权限策略中为 `allow`:脚本本身无副作用,脚本发起的每个嵌套工具调用仍携带 `parentToolCallId` 经过同一权限门裁决;RTK 跳过所有嵌套调用,保证 bash 的 `structuredContent` 原样传给脚本。组合包在 `pi-tool-search/extensions/bundle-groups.ts` 中为自身暴露的工具预置权威分组,包括本地文件导航、SSH 远端文件/命令、Chrome 导航/交互/调试、用户交互、CodeGraph/LSP、Tavily、Exa、Keenable、Memory 查询/维护与 Skill 管理。不可用、已固定或尚未授权而未注册的可选工具会自动从动态组中滤除。
标准组合包的全部隐藏工具都能命中预置目录,因此首次使用不调用模型、不生成用户缓存,也不把完整隐藏 schema 发送给 provider。只有用户另外安装了未识别工具,并且当前调用不是精确加载已有分组时,才可使用当前已认证模型补充目录;精确已有分组始终立即按当前确定性目录激活,不等待无关未知工具的模型增强。模型结果必须保留组合包预置分组,否则直接拒绝。有效增强缓存以 `0600` 写到 agent 目录的 `my-pi/tool-search/catalog-v1.json`,调用用量计入工具结果。用户 `groupOverrides` 的优先级高于预置目录;`/tool-search-rebuild` 会恢复预置目录,`/tool-search-status` 显示目录来源、容量、LRU 顺序和最近淘汰原因。
动态组默认最多同时加载 5 个、每个模型生成组最多 8 个工具、全部动态组最多 28 个工具。`tool_search.groups` 可在一次调用中原子加载最多 5 个精确组;完整请求本身超限时保持原状态。加载或调用组内工具会更新 LRU,超限时先卸载最久未使用且不在本次请求内的组。自然语言 query 对精确工具名和已提交 workflow alias 加权,弱匹配或近似同分只返回候选。首次纯增加载继续使用 Pi 原生增量传播;发生卸载和加载的替换由 Pi 自动走安全 fallback。
Tool Search 的配置文件是已安装组合包内的 `config/tool-search.json`(即本仓库的 `config/tool-search.json`,随 `pi install` / `pi update` 就位,扩展运行时直接读取):
```json
{
"alwaysEnabled": [
"codegraph_explore",
"lsp_diagnostics",
"memory_search",
"session_search",
"memory_add",
"memory_replace",
"memory_remove",
"skill_manage",
"context_tree_query",
"overflow_query",
"codemode"
],
"showToolSearchFooterStatus": false,
"maxActiveGroups": 5,
"maxToolsPerGroup": 8,
"maxDynamicTools": 28,
"groupOverrides": {}
}
```
扩展只读取该文件,从不写入:文件缺失、不可读或结构无效时回退内置的 `BUNDLE_TOOL_SEARCH_DEFAULTS`;对已安装副本的手改不做保护,`pi update` 会覆盖,长期自定义应改仓库 `config/tool-search.json`。`alwaysEnabled` 中的精确工具名属于固定工具,不占动态组额度;`groupOverrides` 可把指定工具强制归入命名组。默认关闭状态行,避免与 minimal footer 叠加。
### 精确读写归 Hashline
组合包固定加载 `pi-hashline-edit@0.8.3`,以带 `LINE#HASH` 行锚点的实现覆盖 Pi 内置 `read` 和 `edit`。`extensions/hashline.ts` 在加载扩展前把 `config/pi-hashline-edit.json` 同步到 `~/.pi/agent/hashline.json`:`hashLength` 保持最小的 `2`,`grep` 强制关闭以避免与 FFF 冲突,`replaceText` 关闭以要求修改使用可验证锚点。
Hashline 不负责压缩大文件;每行锚点本身还会增加少量 token。上下文节省来自先用 CodeGraph/LSP 定位,最后只对真正准备修改的区域执行小范围 Hashline `read`。因此不应为了探索、计数、比较或总结而直接读取完整大文件。
### 搜索归 FFF
`extensions/fff-override.ts` 强制设置 FFF 官方的 `PI_FFF_MODE=override`(显式传入
`--fff-mode` 仍按 FFF 官方优先级覆盖它)。FFF 替换
Pi 的 `find` 和 `grep`,并提供 `multi_grep`;RTK 对所有 `grep` 工具结果直接跳过,
也默认关闭 Bash 命令改写,因此不会把 `rg`、`grep`、`find` 或 `fd` 改写到 RTK。
### 输出压缩归 RTK
RTK 保留 Bash、read、build、test、lint 和 Git 输出压缩。默认 `read` 的有损压缩
仍关闭;可用 `/rtk` 查看或调整。旧机器已有的 RTK 配置若没有
`commandRewritingEnabled` 字段,也会按 `false` 归一化,不需要迁移配置。
### 大输出归 pi-overflow
新工具结果的展示截断统一由 `pi-overflow` 负责:超阈值的原文落盘、模型只看到
「头 + 信号行 + 尾」的有界视图,需要原文时用 `overflow_query` 检索(详见下文
「Pi Overflow」小节)。FFF 仍负责精确字面搜索;RTK 继续对 Bash、build、test、lint
和 Git 输出做语义压缩,其兜底硬截断已关闭。
### SSH 服务器配置
`pi-ssh` 运行时使用纯 `ssh2`,不依赖系统 `ssh` 或 `sshpass`。首次使用前显式导入需要的 OpenSSH alias:
```bash
./configure.sh ssh import packaging-server
```
脚本只在导入阶段调用 `ssh -G` 解析用户选中的 alias,随后交互选择 SSH Agent(包括 1Password)、私钥文件或密码认证、显示并确认服务器 Host Key、测试连接,再把完整配置写入 `${XDG_CONFIG_HOME:-$HOME/.config}/my-pi/pi-ssh/hosts.enc`。Agent 模式只保存 socket 路径,私钥仍留在 Agent 中;邻接的随机 `vault.key` 用于 AES-256-GCM 解密,目录与两个文件在 POSIX 上分别是 `700` / `600`。该加密只避免误看或单独泄漏密文,能读取两文件的同一用户仍可解密。
可用 `./configure.sh ssh list|update|remove|rotate-key` 管理已导入主机。第一版拒绝 `ProxyJump` / `ProxyCommand`,且不会自动读取远端 `AGENTS.md` 或 `CLAUDE.md`。连接不再通过 `/ssh`、`--ssh` 或 session resume 建立:用户在具体远端任务中明确指定已导入 host ID 后,Agent 把受复核、串行且可取消的 `ssh_connect` 作为独立步骤调用并等待成功,再使用其他 `ssh_*` 工具;连接动作及后续操作均进入 `ask → auto-review`,相对远端路径会在预览中显示请求值和解析后的绝对路径,会话结束自动断开。SSH transport 在会话内持久,独立命令最多使用 4 路有界并发 exec channel,但每次 `ssh_bash` 都启动独立的非交互 Shell;需要持续改变后续远端操作的工作目录时,Agent 同样必须把受复核且串行执行的 `ssh_cd` 作为独立步骤调用并等待成功,而不是依赖某次 Shell 中临时执行的 `cd`。
远端文件搜索使用独立的 `ssh_find` / `ssh_grep`:在每次获批调用内按服务器现有能力选择 `fd/fdfind → git ls-files → find` 或 `rg → git grep → find+grep`,不安装远端软件,并以最大 200 条结果、单行截断和 `truncated` 标记约束返回。搜索目标作为绝对参数与当前远端执行 cwd 分离,因此 `ssh_grep` 可直接搜索单个文件而不会尝试把文件当目录进入;30 秒超时会报告解析后的 root 并提示先用 `ssh_find` 缩小范围。远端 HOME/cwd 通过可取消、有界随机标记探测获得,畸形结果不会更新连接状态。RTK 只压缩 `ssh_bash` 的非搜索输出,不改写远端命令,也不处理 `ssh_find`、`ssh_grep` 或 `ssh_read`。详细说明见 [`pi-ssh/README.md`](pi-ssh/README.md)。
### 在线搜索服务
运行 `./configure.sh search` 可用隐藏输入依次配置 Tavily、Exa 和 Keenable;key 不得出现在命令行参数中,非交互方式从标准输入读取(每次调用最多一个 provider):
```bash
printf '%s' "$TAVILY_API_KEY" | ./configure.sh search --tavily -
```
只传部分参数时保留其他服务的已有值。凭据写入 Pi 自己的
`auth.json`(`$PI_CODING_AGENT_DIR/auth.json`,默认 `~/.pi/agent/auth.json`,权限 `600`):
每个 provider 一条 `{ "type": "api_key", "key": "..." }` 条目,原子加锁写入,
其他条目(如 OAuth 凭据)原样保留。`--list` 只显示配置状态、不回显 key;
`--migrate` 可从旧的 `search.env` 导入缺失条目;`--auth FILE` 可覆盖文件路径。
key 值支持 auth.json 原生解析语义:`$VAR` / `${VAR}` 环境变量插值、`!command`
执行命令取 stdout(如 `"!op read op://Vault/Tavily/key"`)、`$$` / `$!` 转义。
显式进程环境变量因此不再被直接读取——需要 env 注入时把 key 写成
`"$TAVILY_API_KEY"` 即可。`KEENABLE_API_URL`(非 secret 的端点覆盖)仍走
进程环境变量,也可放在 keenable 凭据的 `env` 字段中。
三个服务由本仓库自维护的 `pi-web-search/` 统一封装:对模型只暴露 `web_search` / `web_fetch` 两个工具,schema 与提示词中不出现任何厂商名;每次 `web_search` 先由当前主模型(`ctx.model` + `ctx.modelRegistry.complete`,零额外配置)按内置路由规则在候选厂商中选一个,再按统一参数翻译后调用,`details` 记录实际 provider 与路由方式;选择结果按会话内 LRU 缓存,路由失败或被选厂商报错时按可用性顺序自动降级。`web_fetch` 固定调用 Exa 的 `web_fetch_exa` 提取正文(默认每页 3000 字符上限),失败时静默降级到 Keenable、再到 Tavily。
`pi-web-search/clients/` 全部是纯 `fetch` 实现,三个 key 统一由 `pi-web-search/auth.ts` 从 auth.json 解析(Tavily 直连 `api.tavily.com/search|extract`,必须有 `tavily` 凭据,无 key 时不参与路由;Keenable 复刻上游 client,默认走 keyless `/public` 端点,`keenable` 凭据只提高速率限制并保留 SSRF host 防护;Exa 直接对 `https://mcp.exa.ai/mcp` 发 JSON-RPC——initialize 一次并缓存 `mcp-session-id`、随后 `tools/call`,会话失效(HTTP 404)自动重建,`exa` 凭据只通过 `x-api-key` 请求头发送,不再依赖 `pi-mcp-adapter`)。Exa 搜索统一走 `web_search_advanced_exa` 并显式限制结果数量与 `textMaxCharacters`,避免响应过大。
### CodeGraph 是原生工具
`extensions/codegraph.ts` 注册原生 `codegraph_explore` 工具,不走 MCP adapter/SDK:每个索引根
惰性启动一个常驻 `codegraph serve --mcp -p <root>` 子进程,由组合包自有的
`extensions/codegraph-client.ts` 以逐行 JSON-RPC over stdio 直连(与 `pi-web-search` 直连 Exa
同一思路),`initialize` → `tools/list` → 每次调用一次 `tools/call`。`projectPath` 缺省为会话 cwd,
沿目录向上寻找最近的 `.codegraph/codegraph.db` 决定索引根;调用参数只透传上游
`inputSchema` 声明的属性。
与一次性 `codegraph explore` CLI 不同,serve 进程内置文件监听会自动同步索引,新符号数秒内
可搜到,因此扩展不再做结果缓存。子进程闲置 10 分钟或会话结束时关闭;调用因子进程死亡失败时
换新客户端透明重试一次。serve 可能拉起 CodeGraph 自己的 daemon(`.codegraph/daemon.sock`),
子进程退出后最多再驻留 5 分钟——这是上游行为,组合包不管理它。
若目标目录没有索引,工具先弹出确认;用户同意后运行 `codegraph init` 并自动重试本次调用,
拒绝一次后本会话不再询问;CLI 不可用或服务调用失败时把结果打回并提示改用
`find`/`grep`/`read`/LSP,不影响其他扩展。索引状态可在项目内自行检查:
```bash
codegraph status
```
### 统一权限系统、硬防御与 AutoReview
`pi-permission-system/` 从上游 `pi-permission-system-v26.2.1` tag 导入,初始源码快照为 `ec4fdb11343dc94f7185b113e559a4cf9f8dc035`。原 `pi-permission-auto-review` 的 reviewer、可信证据边界和 Codex Guardian 风格策略已整合进同一个扩展;其 MIT 许可和来源记录保留在 `pi-permission-system/LICENSES/` 与 `docs/auto-review/`。根组合包不再加载第二个 AutoReview 扩展。
`extensions/permission-system.ts` 只加载扩展本身,不做任何配置播种或迁移;扩展运行时直接读取已安装组合包内的两份 JSONC:
- `config/pi-permission-policy.jsonc`:唯一的全局普通 allow/ask/deny 策略,同时保存运行参数与 AutoReview 配置。项目级 `.pi/extensions/pi-permission-system/policy.jsonc` 不再读取。
- `config/pi-permission-hard-guards.jsonc`:仅全局生效的硬防御。硬 `deny` 先于 Session grant、per-agent 规则和 AutoReview,不能被后续层放宽。
- 同一文件内的 `protectedWrites`:Pi 凭据/全局设置/模型配置、已安装组合包与扩展目录、pi-ssh 凭据库等受保护文件的写入永远走人工确认——不经 AutoReview、yolo 或 Session grant,弹窗没有「本会话允许」选项,没有可用确认界面时直接拒绝。读取不受影响,`ssh_bash` 等远端 shell 工具不参与本机路径保护。
普通 pattern 不再按“最后一条命中”覆盖,而按具体度选择:精确匹配优先,其次字面字符更多、通配符更少、pattern 更长,只有完全同级时才以后声明者为准。因此具体 deny 会稳定压过宽泛的 `"*": "allow"`。
系统不再产生 `external_directory` 判断:项目外路径与项目内路径一样,只走用户配置的工具、`path` 和 Bash 规则。Tool Search 是唯一的工具显隐/激活控制者;权限系统只在工具被调用时做裁决。
`<agentDir>/my-pi/` 只保留可随时丢弃的运行时状态(如权限日志、Tool Search 目录缓存);组合包配置一律位于仓库 `config/` 并随组合包发布,对已安装副本的本地改动由 `pi update` 覆盖,要长期保留的自定义必须改仓库 `config/` 下的权威源。旧位置 `~/.pi/agent/extensions/pi-permission-system/` 的残留文件被忽略,不迁移也不清理。
默认普通策略对未匹配请求返回 `ask`,并通过 `authorizerChain: ["auto-review"]` 先交给内置 reviewer。高危 Hard Guard 直接终止;AutoReview 的 `allow` / `deny` 对任一普通策略 `ask`(包括 `path`)直接结束当前审批;模型、配置、认证、超时或输出异常统一 `defer` 到人工界面。
自动评审模型完全由配置文件决定:`autoReview.provider` 与 `autoReview.model` 都不设内置默认值,扩展也不会合成替代模型。两者任一缺失时,若 `auto-review` 已在 `authorizerChain` 中,`session_start` 会提示一次,之后每个 `ask` 都 `defer` 到人工审批界面;provider 未注册或模型未发布同样 `defer`。`reasoning` 也由配置决定,不设默认常量。
每个 AutoReview `allow` / `deny` 记入权限 review 日志(`defer` 记为 `errorCategory`),日志只保存有界、脱敏的请求标识与风险/授权等级,不保存 rationale、原始工具参数或 transcript。扩展不汇总历史裁决,也不启动任何后台分析 Agent,更不会自动修改策略文件。
SSH 仍复用同一权限入口:`ssh_connect`、远端路径工具默认为 `ask`,`ssh_bash` 映射完整 Bash 策略并设置 `decisionFloor: "ask"`。硬拒绝不能被 reviewer 覆盖;普通 `defer` 才进入人工兜底。
### TypeScript、Kotlin 与 Java LSP
`extensions/lsp.ts` 会把 `config/lsp.json` 部署到全局 `~/.pi/agent/lsp.json`,其中启用:
- `typescript-language-server@5.3.0 --stdio`:匹配 TypeScript/JavaScript 及 JSX/TSX、MTS/CTS、MJS/CJS;组合包同时固定 `typescript@6.0.3` 作为 `tsserver` 后端。
- `kotlin-lsp --stdio`:匹配 `.kt`、`.kts`。
- `jdtls`:匹配 `.java`;官方 wrapper 会按当前项目工作目录选择 cache data 目录。
TypeScript LSP 通过组合包内 Node 和 `typescript-language-server` CLI 直接启动,不依赖、调用或拉起 VS Code GUI;部署配置时会把包内 CLI 的绝对路径写入全局配置。它优先使用项目自身可用的 TypeScript,否则回退到组合包固定的 TypeScript 6 后端。
Kotlin 与 Java 按 Gradle、Maven 或 Git marker 定位项目根,忽略常见构建输出,并为大型 Android/Gradle
项目预留 120 秒启动时间。Kotlin 与 Java 的 language server 可执行文件不由根包安装;使用前需
确保 `kotlin-lsp` 和 `jdtls` 位于启动 Pi 的 `PATH`。Kotlin 官方 Homebrew 安装方式为:
```bash
brew install JetBrains/utils/kotlin-lsp
```
JDT LS 需要 Java 21 或更高版本;可使用带 `jdtls` wrapper 的官方发行包或系统包。
### 持久记忆(pi-hermes-memory)
组合包加载仓库内 `pi-hermes-memory` 源码并注册六个工具:
| 工具 | 作用 |
|---|---|
| `memory_search` | 检索持久记忆:全局、用户、项目、失败四类 |
| `session_search` | 在 SQLite FTS5 trigram 索引中检索历史会话原话 |
| `memory_add` | 新增一条持久记忆 |
| `memory_replace` | 按子串匹配修改已有记忆 |
| `memory_remove` | 按子串匹配删除已有记忆 |
| `skill_manage` | 创建、查看、修补、重写或删除 `SKILL.md` 过程记忆 |
默认 `policy-only` 模式不在 system prompt 中注入记忆正文,只注入 `<memory-policy>` 指令告诉模型何时
检索、何时写入。因此首轮 token 成本很低,也保持 prompt 前缀稳定。写工具只写扩展自己的数据目录,
不触碰工作区。
`skill_manage` 是扩展提供的能力:Pi 宿主只负责发现并加载 skill 目录,本身没有创建 skill 的工具。
该扩展同时注册 `~/.pi/agent/projects-memory/<项目>/skills/` 供 Pi 发现,因此不加载它时,这些既有
skill 也不会出现在 Pi 的 skill 索引中。
记忆与 skill 位于 `~/.pi/agent/pi-hermes-memory/`(全局)和 `~/.pi/agent/projects-memory/<项目>/`
(项目级)。这些是用户数据:安装、升级和卸载脚本都
不会创建、迁移或删除它们,也不会自动转换旧 Hippo `.hippo/` 数据;扩展配置来自已安装组合包的
`config/pi-hermes-memory.json`。
### Kitty 完成与权限确认通知
`pi-notify/` 直接加载本地维护源码。完成通知只在交互式 TUI 中监听 `agent_settled`,因此自动重试、自动
compaction 和排队 follow-up 完成前不会提前通知;同时监听 `pi-permission-system` 的
`permissions:ui_prompt`,仅在权限系统即将显示人工确认界面时立即通知,策略或 AutoReview 已直接完成的
决定不会通知。Kitty 后端使用 Base64 OSC 99、每个 Pi Session 独立的稳定通知 ID、显式 `a=focus`,
并默认设置 `o=always`:即使来源 Kitty window/pane 正在接收键盘输入也会显示通知,点击通知由 Kitty
返回原始来源;仍可通过 `visibility` 改用 `unfocused` 或 `invisible`。
默认忽略不足 3 秒的短任务,但权限确认通知不受该时长门槛影响。`/notify on|off|test|status` 可控制
当前 Session 的两类通知;持久默认通过组合包 `config/pi-notify.json` 的 `enabled`、`minSeconds`、
`visibility`、`action`、`messageSource` 等字段配置。`messageSource: "none"`
会同时隐藏回复摘要以及权限值和请求者细节。Kitty 位于 tmux 内时需要
`set -g allow-passthrough all` 并重启 tmux server。完整配置和上游差异见
[`pi-notify/README.md`](pi-notify/README.md)。
### Pi Compaction
组合包只加载仓库内维护的 `pi-compaction/`。它管理已经进入 Session 的历史投影:上下文压力达到阈值时,在 `turn_end` 批量提交 Pi 原生 `context_edit`,把最近 `keepRecentTurns` 轮之外的大型工具结果遮蔽为指向 `context_tree_query` 的单行占位符;遮蔽成批发生、受 trigger/target 回差与 `minClearTokens` 约束。原始工具结果保留在 Session 中(UI、导出不变),可通过 `context_tree_query` 按 tool call ID 有界恢复。
普通 Provider、阈值判断、Codex native compaction、`/context`、`/compaction-status` 和 minimal footer 都读取同一个 effective projection snapshot。整段摘要只在空闲 `agent_settled` 且达到绝对 token 阈值(默认 400K,受窗口比例约束,272K 窗口时约为 90%)时经 `ctx.compact` 触发一次;Pi 自身的阈值压缩作为最终安全网始终有效,`session_before_compact` 不再按扩展自身阈值取消。Codex native API 直接消费 effective ResponseItems,同时保存有界 portable summary 供模型或 Provider 切换。
唯一配置位于已安装组合包的 `config/pi-compaction.json`:`masking` 段为遮蔽触发/目标阈值、`keepRecentTurns`、`minEntryTokens` 与 `excludeTools`,`summary` 段为整段摘要阈值与 thinking 档位,扩展只在内存中归一化且不写回配置。`/compaction-status` 显示 raw/effective/reclaimed token、置信度、segment 和已遮蔽结果数。完整配置、Session version 1 格式和双上游来源见 [`pi-compaction/README.md`](pi-compaction/README.md) 与 [`pi-compaction/UPSTREAM.md`](pi-compaction/UPSTREAM.md)。
原生远程压缩同时支持 `openai-codex` + `openai-codex-responses` 和 `sub-api` + `openai-responses`,使用触发时当前会话模型。SubAPI 保留现有模型配置,从 `baseUrl` 调用公共 `/responses` 并使用 `compaction_trigger` 流式协议;优先保留非空显式 `Authorization`,否则使用 API key,也支持仅凭非空 `cf-aig-authorization` 的代理认证。缺失或空白凭据在请求前拒绝。SubAPI 不要求客户端解析 ChatGPT account ID,也不调用独立 `/responses/compact`;Codex 的 JWT 要求保持不变。网关部署须支持 Sub2API 原生压缩 v2;请求失败沿用 Pi 回退,切换模型或 Provider 时使用 portable summary。
本实现不读取或迁移旧 `contextPrune`、`context-prune-*` 或旧 Codex native checkpoint;切换后应创建新 Session。它与 pi-overflow 职责互补:pi-overflow 在新工具结果进入会话时即截断展示,Pi Compaction 管理已经进入会话的长期历史。
### Pi Overflow
组合包自维护的 `pi-overflow/` 统一负责「每个新工具结果给模型看多少」。它有两个入口:`capture.ts` 排在 `pi.extensions` 最前,只把原始结果文本暂存到进程内 Map(容量 64),绝不修改结果;`index.ts` 排在 `system-prompt.ts` 之前、所有其他扩展之后,此时 RTK 等 handler 已经完成变换——它用最终可见文本判断是否超阈值,落盘的原文取 bash 的 `details.fullOutputPath` 文件、暂存原文或当前文本三者中的最完整版本,视图与其中的行号则一律基于落盘原文生成,保证与 `overflow_query` 读取的内容一致。
当最终文本仍超过 `thresholdChars`(默认 24000)时,模型看到的是确定性的「头部 40 行 + 中段匹配 error/warn 等信号行(至多 40 条)+ 尾部 120 行」视图,并写入 `details.overflow.id`;当上游已把结果压短但原文超阈值时,只追加一行 `[pi-overflow id=…]` 恢复标记。原文以 `sha1(sessionId+toolCallId)` 前 12 位 hex 为 id 存入 `<agentDir>/my-pi/pi-overflow/`(目录 `700`、文件 `600`、原子写入),session 启动时按 `retentionDays`/`maxStoreBytes` 清理。模型可用 `overflow_query` 按 id 正则搜索(带上下文合并)、按行区间或 `jsonPath` 读取;`read`/`edit`/`write`/`overflow_query`/`ask_user_question` 与嵌套调用永远豁免。配置为组合包内 `config/pi-overflow.json`,详见 [`pi-overflow/README.md`](pi-overflow/README.md)。
RTK 的兜底截断与 pi-chrome 的 30K 字符截断已收编进本扩展:`config/rtk-optimizer.json` 中 `outputCompaction.truncate.enabled` 默认关闭,chrome_* 工具返回完整文本;pi-web-search 的 `web_fetch` 默认 `max_characters` 提高到 20000(上限 100000),`web_search` 的 `max_results` 约束在 1–20。