# my-pi

个人维护的 Pi 扩展组合包。安装一次即可加载并配置：

- `@ff-labs/pi-fff@0.10.5`：使用官方 `override` 模式接管 `find`、`grep` 和 `multi_grep`。
- 本仓库维护的 `pi-rtk-optimizer`：只处理 Bash/read 等输出压缩，默认不改写命令，也不处理搜索工具结果。
- `context-mode@1.0.169`：通过 Pi adapter 提供 `ctx_*` 工具、上下文隔离和会话连续性。
- `@tavily/pi-extension@0.1.2`：提供 Tavily 广泛搜索与页面提取；通过本地 override 暴露为 `tavily_web_search` / `tavily_web_fetch`。
- `@keenable/pi-search@0.1.2`：提供紧凑的 `keenable_search` / `keenable_fetch`，并加载其搜索 skill；API key 可选。
- `pi-mcp-adapter@2.26.0`：通过单个共享 adapter 实例接入机器现有的 CodeGraph 和 Exa 托管 MCP，避免重复注册 Pi 的全局 MCP flag 与命令。
- `pi-context-view@0.4.2`：查看上下文占用。
- `@firstpick/pi-extension-codex-fast-mode@0.1.1`：为 Codex provider 提供会话级 `/fast-mode`。
- `pi-lsp@0.1.7`：为 TypeScript/JavaScript、Kotlin 和 Java 提供 LSP 诊断、跳转与符号工具；TypeScript 后端由组合包内置。
- `pi-hermes-memory@0.9.6`：提供持久记忆、会话搜索和 secret scanning。
- `@ogulcancelik/pi-codex-compaction@0.1.3`：为 `openai-codex` 提供原生远程压缩。
- `@ogulcancelik/pi-minimal-footer@0.1.10`：用紧凑的上下文仪表和订阅用量条替换默认 footer。
- `pi-condense@2.9.1`：把已完成的工具调用批次总结为可恢复的短摘要，并通过 `context_tree_query` 按需取回原始输出；组合包首次加载时默认开启。
- 本仓库维护的 `pi-permission-auto-review`：作为 `pi-permission-system` authorizer，使用 Codex Guardian 风格策略自动复核 `ask` 请求。
- 本仓库维护的 `pi-permission-system`：从 `@gotgenes/pi-permission-system@26.2.1` 源码导入，负责工具、路径、MCP、硬拒绝和兜底权限基线。
- `extensions/tool-routing.ts`：保留 Pi 默认系统提示词，并按当前激活工具追加简短的工具与搜索路由规则；提供 `/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。

脚本首次实际改动 `.zshrc` 前会在同目录创建带时间戳的备份。Oh My Zsh loader、
Powerlevel10k 主题/配置和各 Zsh 插件使用 `# >>> my-pi:<id> >>>` 到
`# <<< my-pi:<id> <<<` 的受管块协议；以后只替换块内内容，块外用户配置保持不变。
标记缺失、重复或不完整时脚本会拒绝修改。若机器没有所需的 Homebrew、`curl` 或 `git`，
脚本会保留已完成的安装结果、继续检查其他项目，并最终返回非零状态。
`rtk` 只供默认关闭的命令改写使用，因此不会作为必装依赖检查。

也可以绕过脚本，直接运行上面的 `pi install` 命令，此时机器级 CLI 不会被检查。

升级已安装的组合包请使用独立脚本：

```bash
./update.sh
```

升级脚本先执行：

```bash
pi update git:git@bitbucket.org:siakitem/my-pi.git
```

随后只处理已经安装的项目，未安装项直接跳过且不会询问安装：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` 后的已安装组合包目录读取最新 `config/p10k.zsh`，再与受管副本比较，
只在内容不同时备份并原子同步；`.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` 使用精确版本，`package-lock.json` 固定完整依赖树。不要再用项目级
`.pi/settings.json` 重复安装这些扩展，否则同一扩展可能被加载两次。

Hermes Memory 的 SQLite search 依赖 `better-sqlite3` 原生模块；根包只在 `allowScripts` 中
精确放行当前锁定版本的构建脚本。若升级 Hermes 或 `better-sqlite3`，必须同步核对并更新该精确
版本，不能把其他依赖的 install scripts 一并放行。

默认配置不需要系统 `rtk` CLI。只有以后在 `/rtk` 中主动开启
`RTK command rewriting` 时，才需要另外安装 `rtk` 可执行文件。

CodeGraph 本体不由组合包安装。需要使用 CodeGraph 的机器应自行确保 `codegraph` 在
启动 Pi 的 `PATH` 中，并在目标项目执行过 `codegraph init`。组合包不会创建或维护
`.codegraph/`，也不会修改 CodeGraph 的索引、更新或遥测设置。

## 组合行为

### 工具与搜索路由

`extensions/tool-routing.ts` 不替换 Pi 默认系统提示词，而是在每轮开始前根据当前激活工具追加简短规则。代码结构、调用关系和待修改 symbol 优先使用 CodeGraph，定义、引用、类型和修改后诊断优先使用 LSP；仓库字面搜索先用 FFF `find` 缩小文件或目录范围，再在已收敛的路径中用 `grep`/`multi_grep` 获取行号。宽泛搜索命中大量结果、发生截断或达到上限时，应继续缩小路径、glob 或 pattern，而不是提高 limit 或输出全部结果。

在线搜索默认按任务只选一个服务：关键词不确定、新闻/近期话题或需要较多候选来源时优先 Tavily；官方/API 文档、版本信息、论文和高确定性事实确认优先 Exa；中文政策、政府公告、中文网页、站点限定和日期筛选优先 Keenable。只有来源质量或不确定性确实需要时才跨服务复核，避免默认把三套结果全部塞进上下文。

日志、测试/构建输出、工作区内大文件的探索/分析/总结以及不可预测的大输出优先交给 Context Mode。只有确实需要精确源码或准备修改时，才用带 `offset/limit` 的 Hashline `read` 读取最小区域并取得 `LINE#HASH` 锚点，随后用锚定 `edit` 修改；成功编辑返回的新锚点可继续复用，只有锚点过期或下一目标区域尚未展示时才重新读取。已有工具结果足够时停止检索，避免对同一问题依次重复调用 CodeGraph、FFF 和 `read`。

使用 `/dump-system-prompt` 可将当前扩展所见的有效提示词写入当前项目的 `.pi-debug/effective-system-prompt.md`。`.pi-debug/` 属于本地诊断输出，默认不提交。

### 精确读写归 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 定位、再用 Context Mode 隔离分析，最后只对真正准备修改的区域执行小范围 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` 归一化，不需要迁移配置。

### 大输出归 Context Mode

Context Mode 直接加载 npm 包内置的 Pi adapter 和 skills，不需要额外写入
`~/.pi/agent/mcp.json`，也不需要全局安装 `context-mode` 命令。它提供 `ctx_*` 工具，
将批量读取、命令研究和网页内容先在隔离进程中处理，再把收敛后的结果送入上下文。

FFF 仍负责精确字面搜索；RTK 继续压缩未走 Context Mode 的 Bash、build、test、lint
和 Git 输出。Context Mode 不替换这两个扩展的现有配置。

### 在线搜索服务

运行 `./search_config.sh` 可用隐藏输入依次配置 Tavily、Exa 和 Keenable；也可一次无交互配置：

```bash
./search_config.sh --tavily '...' --exa '...' --keenable '...'
```

只传部分参数时保留其他服务的已有值。脚本把 key 原子写入
`${XDG_CONFIG_HOME:-$HOME/.config}/my-pi/search.env` 并设置权限为 `600`；
`MY_PI_SEARCH_CONFIG` 或 `--config` 可覆盖路径。组合包在搜索扩展初始化前加载该文件，
但调用 Pi 时显式传入的同名环境变量优先。配置文件不属于仓库，不会随安装包提交。

Tavily 通过 `extensions/tavily-override.ts` 加载官方扩展。override 只改工具身份，不改官方执行逻辑：上游 `web_search` / `web_fetch` 被注册为 `tavily_web_search` / `tavily_web_fetch`，label 和提示词中的内部工具引用也同步带上 Tavily 标识。使用前需设置 `TAVILY_API_KEY`。Tavily 适合广泛发现，但来源可能混杂且输出较长，应从较小的 `max_results` 开始，非必要不返回 raw content。

Keenable 直接加载 npm 包的扩展和 skill，默认无需 key；设置 `KEENABLE_API_KEY` 可提高速率限制。它适合中文内容、`site` 限定和发布日期筛选。搜索结果保持紧凑，只对选中的 URL 调用 `keenable_fetch`。

`extensions/mcp.ts` 通过单个 `pi-mcp-adapter` 实例同时连接 Exa 与 CodeGraph，避免两个 adapter 重复注册 `--mcp-config`、`/mcp` 和 `/mcp-auth`。其中 Exa 连接 `https://mcp.exa.ai/mcp`，并把 MCP 原始工具映射为统一的来源前缀形式：`exa_web_search`、`exa_web_fetch` 和 `exa_web_search_advanced`。配置 `EXA_API_KEY` 后通过 `x-api-key` 请求头认证，不把 key 放进 URL。Exa 适合官方文档、技术资料、版本信息和论文；高级搜索必须显式限制结果数量与返回文本长度，避免响应过大。

根测试会扫描所有本地扩展入口，强制只有 `extensions/mcp.ts` 可以创建或导入 `pi-mcp-adapter`。新增 MCP 服务必须合并进这个共享实例，不能再增加独立 adapter 入口；隔离 Pi 加载仍作为发布前的运行时验证。

### CodeGraph 只负责连接

同一个 `extensions/mcp.ts` adapter 配置启动
`codegraph serve --mcp`，不会读取或覆盖用户已有的 MCP 配置。连接采用
`keep-alive`，并只把官方当前主工具 `codegraph_explore` 作为同名 Pi 工具暴露；
CodeGraph 的文件 watcher 由该 MCP 进程自身维护。

若机器没有 `codegraph`，或当前项目尚未建立索引，CodeGraph 会报告连接/初始化错误，
其他扩展仍可正常工作。安装与索引状态可在机器上自行检查：

```bash
codegraph --version
codegraph status
```

### 权限基线自动部署

`pi-permission-system/` 从上游 `pi-permission-system-v26.2.1` tag 导入，初始源码快照为 `ec4fdb11343dc94f7185b113e559a4cf9f8dc035`。根包通过本地 `file:` 依赖提供其运行时依赖，并由包装入口直接加载仓库源码，不再加载 npm 包中的实现。

`extensions/permission-system.ts` 在权限扩展注册前，把仓库中的
`config/pi-permission-system.json` 同步到 Pi agent 目录。仓库文件是权威配置；直接在
运行目录通过 UI 修改的策略会在下次加载组合包时被覆盖，长期调整应提交到本仓库。

当前策略按类别划分：

- 默认工具：默认允许，避免常规编码操作反复确认；FFF 的 `grep`、`find`、
  `multi_grep` 明确允许。
- 搜索边界：直接通过 Bash 调用 `rg`、`grep`、`find`、`fd`、`git grep` 拒绝，统一走 FFF。
- 路径与凭据：外部目录询问；环境文件、SSH/GPG、云凭据、Keychain 和 Pi 认证文件拒绝；
  `.env.example` 作为无密钥模板允许。
- Git：状态、diff、日志、对象查看等只读命令允许；其他 Git 命令进入 `ask`，由自动复核 authorizer 裁决。
- Bash 变更操作：Git 非只读操作、包管理、文件变更、系统操作、网络访问和环境导出均由权限基线先判定；命中 `ask` 后再进入自动复核。
- MCP 与 Skill：列举 MCP 状态允许，调用其他 MCP 工具进入 `ask`；本地 Skill 加载允许。

`permissionReviewLog` 已开启，后续可依据真实命中记录继续收敛规则。

### Permission Auto Review 与权限基线的边界

`pi-permission-auto-review/` 从上游源码仓库的 `@mzwing/pi-permission-auto-review@0.2.0` tag 导入，初始源码快照为 `8d196e4ef0884cac8326c366191dad3f585d470a`。该目录与 `pi-rtk-optimizer/` 一样由本仓库直接维护，不依赖 npm 中的预编译扩展包。

扩展以 `auto-review` 名称注册到 `pi-permission-system` 的 authorizer chain。只有权限基线先得到 `ask` 时才调用 reviewer：模型返回 `allow` 时自动批准，返回 `deny` 时直接拒绝，配置、模型、认证、超时或响应异常时返回 `defer` 并继续走正常人工提示。这样只有一条权限链，不再存在两个独立 `tool_call` gate 造成的重复审批。

边界保持如下：

- `allow`：权限基线已明确允许的常规操作不会调用 reviewer。
- `deny`：Bash 直搜、敏感凭据路径等硬拒绝不会交给 reviewer，也不能被其绕过。
- `ask`：Git 非只读操作、包管理、文件/系统/网络/环境操作和普通 MCP 调用交给 reviewer；`path` 仍全部受 delegation envelope 保护。`external_directory` 仅允许内置 `read` 接受 reviewer 的 `allow`，`write`、`edit`、Bash、未知工具及其他外部目录访问仍降级为人工确认。

reviewer 默认使用 `openai-codex/codex-auto-review`、low reasoning 和内置 Codex Guardian 风格策略，并读取当前 session active branch 中的可信用户证据。可通过 `/permission-auto-review` 查看或调整全局/项目配置；无配置时使用源码内置默认值。

### 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 的官方发行包或系统包。

### Hermes Memory

Hermes Memory 使用上游默认的 `policy-only` 模式：不把完整记忆直接注入每轮上下文，由工具按需
搜索；同时启用后台复核、自动 consolidation、session search 和 secret scanning。首次需要检索
旧会话时运行 `/memory-index-sessions`。

### Codex 原生远程压缩

远程压缩只对 `openai-codex/openai-codex-responses` 生效，使用上游默认配置：在 turn boundary
达到 90% 上下文占用时触发，并写入 Pi 原生 compaction boundary。失败时保持原历史且不静默
回退到文本摘要；checkpoint 与创建它的 Codex model 绑定。

### Pi Condense

组合包首次加载时会在 `contextPrune.enabled` 尚未配置的情况下写入 `true`，因此 `pi-condense` 默认开启；用户通过 `/pruner off` 写入的显式 `false` 会被保留，后续启动或升级不会重新覆盖。它使用上游默认的 `agent-message` 触发模式：同一用户任务中的多轮工具调用会在最终文本回复后统一触发整理，默认仍按每个 assistant turn 分别生成摘要；后续上下文只保留摘要和 `t1`、`t2` 等引用。需要原文时，模型可调用 `context_tree_query({ toolCallIds: ["t1"] })` 恢复。

常用命令：`/pruner status` 查看状态，`/pruner settings` 调整配置，`/pruner now` 立即处理待总结批次，`/pruner tree` 浏览已归档调用，`/pruner stats` 查看累计成本和节省，`/pruner off` 关闭。配置保存在 Pi agent 目录 `settings.json` 的 `contextPrune` 字段。建议保留默认的 skill 路径保护，并把必须逐字复用输出的工具加入 `protectedTools`。

它与 Context Mode 的职责不同：Context Mode 避免大型原始输出进入当前模型上下文，Pi Condense 则压缩已经进入会话、且已完成使用的历史工具结果。它也不替代 Codex 原生远程 compaction；不希望自动整理历史时可运行 `/pruner off`。

### Codex fast mode

该扩展只在 `openai-codex` provider 的 Responses 请求上加入
`service_tier: "priority"`。使用 `/fast-mode on|off|status` 控制当前会话，不影响
其他 provider。
