pi-edit-fuzzy

pi edit 容错修复钩子:edit 执行前修复 oldText 漂移(空白/缩进/转义/CJK 标点,两档 pass 链),失败后增强错误候选反馈;不替换原生 edit 工具。

Packages

Package details

extension

Install pi-edit-fuzzy from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:pi-edit-fuzzy
Package
pi-edit-fuzzy
Version
0.1.0
Published
Oct 31, 2026
Downloads
373/mo · 373/wk
Author
jsonsong
License
MIT
Types
extension
Size
58.7 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-edit-fuzzy

pi 的 edit 工具容错修复扩展:不替换原生 edit,通过 tool_call / tool_result 两个事件钩子,在 edit 执行前修复模型漂移的 oldText(空白/缩进/转义/CJK 标点), 在 edit 失败后增强错误反馈(最近候选 + 相似度 + 行号),把「失败 → 盲重试」循环 压缩为「一次修复命中」。

安装

pi install ./packages/edit-fuzzy              # 本地安装(仓库内路径)
pi install npm:pi-edit-fuzzy                  # 从 npm 安装
pi install npm:pi-edit-fuzzy@0.1.0            # 锁定版本

卸载 = 摘钩子,原生 edit 裸跑,无持久化状态、无文件残留(用户级配置文件除外)。

行为

edit 执行前(tool_call 修复)

  1. 原生优先:原生精确匹配 / fuzzy(NFKC、行尾空白、智能引号等)能命中的 oldText 一律不干预,零开销直通
  2. 原生找不到时,按档位依次尝试修复 pass;修复 = 把 oldText 改写为文件中的 真实文本(改写后必然被原生精确匹配,最终校验与落盘始终由原生完成)
  3. 统一护栏:当前 pass 规则下完整 oldText 有多个候选位置 → 不修,转为 歧义反馈;候选 span 远大于 oldText(> 3×)→ 拒绝;任何钩子异常 → 静默 放行原生路径(fail-open)

edit 执行后(tool_result 增强)

  • 失败(找不到文本):追加最近候选片段 + 文本相似度 + 行号
  • 失败(多处命中):追加全部命中行号
  • 本钩子判定的歧义:追加候选行号,提示补充上下文
  • 成功且有修复:追加一行提示(注明 pass 与 edits 下标),让模型知晓并自我修正

两档修复链

档位 pass 说明
1(默认) line-trimmed / whitespace / indentation / escape / boundary / cjk 确定性变换:行尾空白、行内空格、缩进、字面转义、边界空行、CJK 标点(全量:。,、,《》【】 + NFKC 全角形式,一个 pass 处理完整集合)
2 档 1 + block-anchor / context-aware / multi-occurrence / unicode-normalized 追加启发式:首尾行锚 + 中段相似度、滑窗整体相似度、多候选评分差消歧(top ≥ 0.8 且领先次优 ≥ 0.15)、Unicode 标点归一化

档 2 多候选不再直接放弃:先由评分消歧,差值不足才报歧义。档位只影响匹配宽松 程度,统一护栏(候选唯一/偏大拒绝/原生最终校验)两档都在。

配置

启动时初始化一次(session 重启重读);/edit-fuzzy 可随时查看并重读。

用户级 ~/.pi/agent/pi-edit-fuzzy.json(不存在则首次启动自动创建默认值):

{
	"level": 1,
	"enabled": true,
	"log": false
}

项目级 <项目>/.pi/agent/pi-edit-fuzzy.json(只读,字段级覆盖用户级):

{
	"level": 2
}
  • level:1 或 2,缺省 1
  • enabled:false = 钩子全部直通(等价禁用包但不摘载)
  • log:true = 写内测日志 ~/.pi/agent/logs/edit-fuzzy.jsonl(每次 edit 调用一行,含 pass 触发、原生 edit 异常、钩子自身异常;写失败静默不反噬主流程)
  • 文件不存在 / JSON 非法 / 字段类型错 → 缺省值 + 一行警告,不阻断加载

命令

/edit-fuzzy        # 查看当前配置并从磁盘重读(改文件后免重启)
/edit-fuzzy 1|2    # 切换档位(写入用户级文件并立即生效)
/edit-fuzzy on|off # 开关(写入用户级文件并立即生效)
/edit-fuzzy log    # 切换内测日志(写入用户级文件并立即生效)

日志分析(内测):仓库内 packages/edit-fuzzy/test/log-analysis.test.ts 读取该 JSONL 打印 pass 命中率 / 修复有效性 / 漏检样本;pnpm vitest run packages/edit-fuzzy, 日志文件不存在时自动 skip。

限制

  • 不做 replaceAll(需改工具 schema,钩子层无法实现)
  • 只修 oldText,不改写 newText(含缩进容错场景:模型把 oldText/newText 缩进一起写少时,新代码可能少缩进,成功提示会提醒模型自查)
  • 接受极低概率的误匹配残余风险(唯一候选仍可能不符合模型意图);修复后的 diff 查看与验证是最终保障
  • 超大文件 / 超长 oldText 会跳过评分类 pass(成本护栏),宁可让原生失败

与上游对比

  • 与 pi-semantic-edit 的能力对比 台账见本包 DELTA.md(pass 设计移植自其思想,本包以事件钩子而非工具替换 的方式承接)

License

MIT