云服务部-叶林立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
2026-08-28 12:18:06 +08:00

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 导出当前有效提示词。

安装、升级与卸载

推荐从仓库检出目录运行安装脚本:

./install.sh

脚本会先执行:

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 不会被检查。

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

./update.sh

升级脚本先把 Pi 本体同步到最新发布版本,再升级组合包:

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 受管块,不触碰块外配置。因此安装流程负责补齐缺失项,升级流程只升级已安装项。

卸载组合包:

./uninstall.sh

卸载脚本只调用 pi remove,不会删除 Kitty、终端主题、Oh My Zsh、Powerlevel10k、Zsh 插件、CodeGraph、Kotlin LSP、JDT LS 或 Java,因为这些用户环境或机器级工具可能仍被其他 项目使用。三个脚本都可通过 PI_PACKAGE_SOURCE 覆盖默认包源, 例如在本地检出中测试:

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 就位,扩展运行时直接读取):

{
  "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:

./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。

在线搜索服务

运行 ./configure.sh search 可用隐藏输入依次配置 Tavily、Exa 和 Keenable;key 不得出现在命令行参数中,非交互方式从标准输入读取(每次调用最多一个 provider):

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,不影响其他扩展。索引状态可在项目内自行检查:

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 安装方式为:

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 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/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。

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。

S
Description
No description provided
Readme
7.9 MiB
Languages
TypeScript 92.7%
JavaScript 3.4%
Shell 2%
HTML 1.8%
Mermaid 0.1%