oh-my-opencode-slim 的 search-path-guard:在 tool.execute.before 中精准拦截无效 grep/glob 搜索路径

发布时间:2026/9/25 3:24:56
oh-my-opencode-slim 的 search-path-guard:在 tool.execute.before 中精准拦截无效 grep/glob 搜索路径 人工智能AI AgentAgent 编排AI 技能【免费下载链接】oh-my-opencode-slimLean, fine tuned Opencode multi agent suite · Mix any models · Auto delegate tasks项目地址https://gitcode.com/gh_mirrors/oh/oh-my-opencode-slim点击查看免费下载导读在 OpenCode 多智能体插件体系里grep与glob是 Agent 检索仓库信息最频繁调用的宿主工具而一旦路径参数指向不存在或结构非法的位置宿主只会抛出一条晦涩难懂的ripgrep execution failed错误让排查无从下手。oh-my-opencode-slim 通过src/hooks/search-path-guard/这个tool.execute.before钩子在搜索工具真正执行之前完成路径解析、文件系统校验与分级错误报告把宿主失败提前转化为可行动的提示。读完本文你将掌握该钩子的设计骨架、路径解析的宿主语义细节、错误分类策略以及它如何在插件主流程中与其他钩子协同并可通过仓库中的完整测试用例复现每一种拦截与放行行为。钩子的职责边界只服务 grep 与 globsearch-path-guard 的全部职责可以浓缩为一句话在宿主工具执行前校验搜索路径防止 ripgrep 执行失败。它挂载在tool.execute.before阶段拦截范围被刻意收窄为grep与glob两类工具源码见 index.ts 中的if (input.tool ! grep input.tool ! glob) return;从而实现对搜索操作的高精度路径校验同时避免干扰其他工具类别——例如read、bash、write等工具的路径参数完全不受影响这一点在测试中也有明确覆盖。钩子要解决的三类痛点非常具体路径存在性解析后的路径必须真实存在ENOTDIR路径某个组成部分不是目录这类非法路径要给出可行动的报错而不是让宿主把原始错误抛给调用者错误可读性缺失路径要上报带指引的帮助信息替代晦涩的ripgrep execution failed宿主语义对齐路径解析必须严格镜像宿主工具各自的语义——v1 的 grep 使用path.joinv1 的 glob 使用path.resolve而 v2 宿主对两者都使用path.resolve。核心架构工厂函数 可注入路径操作钩子的整体结构是标准插件钩子工厂模式codemap.mdcreateSearchPathGuardHook(ctx)接收PluginInput含ctx.directory与可选的ctx.hostFlavor返回tool.execute.before处理器resolveSearchPath()实现与宿主工具逐字节对齐的路径解析规则Path 参数提取只从工具调用的args.path中取值Stat 校验通过fs.statSync做文件系统检查并按错误码分派处理错误上报依据错误类型给出带实操指引的提示。值得强调的是无外部配置的设计取向行为完全由宿主 flavor 探测驱动不需要用户维护任何额外配置文件。两个可注入/可探测的入口分别是hostFlavor可选参数用于 v1/v2 宿主差异与pathOperations注入的路径工具专为确定性测试设计。resolveSearchPath 的精确实现路径解析是全部语义的核心源码实现index.ts如下export function resolveSearchPath( tool: string, hostFlavor: string | undefined, directory: string | undefined, raw: string, pathOperations: PathOperations path, ): string | null { if (!directory) return null; if (pathOperations.isAbsolute(raw)) return raw; if (hostFlavor v2 || tool glob) { return pathOperations.resolve(directory, raw); } return pathOperations.join(directory, raw); }几个关键设计决策无基准目录则保守放行ctx.directory不可用时返回null上层据此绝不拦截注释明确写着 Without a resolution base, never block (conservative fallback)避免在缺少工作区上下文时误伤正常调用绝对路径快速通道isAbsolute(raw)为真时原样返回跳过拼接逻辑——这既是性能优化也保证绝对路径不会因 join/resolve 的语义差异而被错误改写v1 与 v2 的差异被精确复刻v1 grep 走join、v1 glob 走resolve、v2 一律走resolve。这个区别在 Windows 上尤其重要因为join与resolve对驱动器相对路径如C:src的处理结果完全不同。源码注释明确点出Without a resolution base, never block 之外还特别提到这是为了对齐宿主Mirror each host tools resolution rule exactly... that distinction matters for relative paths on Windows, including drive-relative paths such asC:src.错误处理策略ENOENT 上报、ENOTDIR 阻断、其余透传钩子的错误分类是它区别于一刀切拦截的关键对应 codemap.md 的 Error Handling Strategy 与 Error Reporting Flow错误码语义钩子行为错误消息示例ENOENT路径含断链的软链接确实不存在上报缺失抛出带指引的错误Search path does not exist: {resolved} (from {raw}). ... Verify the target path, or list its parent directory to find the correct location.ENOTDIR路径的某个组成部分不是目录阻断非法路径抛出明确错误Search path is invalid: {resolved} (from {raw}). A path component is not a directory (ENOTDIR), so the {tool} search was blocked before ripgrep ran. ...其他权限、I/O 等stat 失败但语义不属于上述两类透传保持原始含义绝不误诊不修改、不追加仅记录日志这个三态分流非常克制ENOTDIR与ENOENT是 Agent 最容易踩中的两类错误路径写错、把文件当目录用因此值得在宿主执行前拦截并改写为可行动的提示而权限问题EACCES 等可能是真实的宿主环境限制透传比武断阻断更诚实。源码中的注释佐证了这一点Any other stat failure (permissions or I/O) keeps its original meaning: pass through and never misdiagnose.钩子执行流程总览原文档给出的完整流程自上而下贯穿一次 grep/glob 调用的生命周期Tool execution (grep/glob) ↓ Tool execute before hook ↓ Validate tool type (grep/glob only) ↓ Extract path argument from tool args ↓ Resolve path using host-appropriate resolution ↓ Validate path exists and is accessible ├─ ENOENT → report missing path ├─ ENOTDIR → block invalid path └─ other error → pass through ↓ Proceed with original tool execution (success case)路径解析子流程即上文的resolveSearchPathInput: raw path, directory, hostFlavor ↓ Check if absolute path (return as-is) ↓ Resolve using host-specific logic: - v2 or glob → path.resolve(directory, raw) - v1 grep → path.join(directory, raw) ↓ Return resolved path or null if directory unavailable主流程中的注册顺序一次深思熟虑的编排search-path-guard 并非孤立运行它在插件主入口 src/index.ts 中的注册位置体现了严格的时序考量。createSearchPathGuardHook(ctx)在插件初始化时创建src/index.ts随后被组装进tool.execute.before复合处理器src/index.tstool.execute.before: async (input, output) { await applyPatchtool.execute.before; // Rewrite guessed non-existing absolute paths BEFORE the search guard: // the guard blocks grep/glob on missing paths, so running the rescue // after it would never see a rescuable path (#1143). await absolutePathRescuetool.execute.before; await searchPathGuardtool.execute.before; await taskSessionManagerHooktool.execute.before; // Record a call only after all rejecting before-hooks have accepted it. // In particular, search-path-guard can reject grep/glob before the host // emits tool.execute.after; running the loop guard first would leave a // pending call-key entry with no completion to consume it. await toolLoopGuardtool.execute.before; },这里透露出两个关键协作细节absolute-path-rescue 必须先于 search-path-guard 执行absolute-path-rescue 负责把 Agent 猜错的绝对路径重锚定到工作区真实位置而 guard 会直接阻断不存在的路径。如果两者顺序颠倒被 rescue 视为可挽救的路径在 guard 阶段就会被拦下永远没有机会被改写对应 issue #1143 的教训注释明确说明了这一点tool-loop-guard 必须后于 search-path-guard 执行tool-loop-guard 负责记录工具调用键而 search-path-guard 可能在宿主发出tool.execute.after之前就拒绝 grep/glob。若 loop guard 先记录就会留下一个没有完成事件来消费的悬空调用键pending call-key因此调用记录必须放在所有可能拒绝的 before-hook 接受之后。此外钩子整体通过 src/hooks/index.ts 的 barrel 导出export { createSearchPathGuardHook } from ./search-path-guard;提供给主入口与 apply-patch、absolute-path-rescue、tool-loop-guard 同属工具拦截这一钩子类别见 hooks/codemap.md 的 Hook Categories 表。细节语义字面量、空白与 Windows 驱动路径源码注释与测试共同揭示了几个容易被忽略、但直接影响 Agent 行为的边界语义index.ts宿主不做 trim路径参数按原样使用前后空白是有效字符。因此 padded-missing-dir 会被当作真实路径名参与解析并最终因不存在而被阻断——这符合镜像宿主原则因为宿主从不裁剪路径。测试同时验证了带空白前缀的目录名可以正常通过spaced dir 目录存在时放行字面量undefined/null是普通相对路径上游宿主把它们当作普通相对路径解析schema 描述中的说明并不代表运行时特殊处理因此钩子也按普通路径对待——指向不存在的undefined路径时同样会触发 ENOENT 阻断测试用path.join(tempRoot, undefined)断言了这一行为空字符串与缺失/非字符串参数一律放行args缺失、path缺失、path: 42、path: null、path: 都不会被拦截。其中空字符串解析结果等价于实例目录本身没有可阻断的对象ENOENT 涵盖断链软链接源码注释指出 broken symlink 属于genuine missing path同样上报缺失而非透传这与上游正在修复的行为保持一致。测试验证18 个场景覆盖全部语义分支index.test.ts是理解钩子行为的另一份权威文档它通过mkdtemp构造真实临时目录、注入 fakedirectory/hostFlavor并借助path.win32注入模拟 Windows 语义这正是pathOperations可注入设计的价值——没有 Windows CI 也能确定性验证 Windows 行为。测试矩阵index.test.ts覆盖缺失路径阻断绝对路径不存在grep、相对路径不存在于目录下glob均抛出Search path does not exist且消息包含解析后的完整路径有效路径放行存在的绝对文件grep/glob、存在的相对目录glob均无异常目录缺失保守放行directory为假值时绝不阻断相对路径工具过滤read、bash等非 grep/glob 工具即使路径缺失也直接忽略参数形状容错undefined、空对象、非字符串、null、空字符串均忽略ENOTDIR 阻断把普通文件当路径组成部分reg-file.txt/childgrep 与 glob 均抛出包含not a directory与ENOTDIR的可行动错误join/resolve 语义分离同一相对路径下grep 解析为path.join(directory, raw)而 glob 解析为path.resolve(directory, raw)测试分别断言Windows 驱动相对路径在 win32 平台上C:missing-search-path按各自语义解析v2 的 grep 对C:src使用 win32resolve语义v1 使用join语义通过path.win32注入验证即使跑在非 Windows CI 上。依赖、性能与可观测性依赖清单钩子的依赖极简codemap.mdNode.jsfs.statSync文件系统校验node:pathisAbsolute/join/resolve路径解析且类型上仅Pick这三个方法约束了注入面的范围结构化日志器来自 src/utils/logger.ts 的log()记录验证决策与错误分类该日志器在落盘前统一经过redactSecretsForLog脱敏保证路径等上下文不会泄露凭据插件 SDKPluginInput类型用于钩子注册与hostFlavor/directory上下文获取。性能设计早期过滤只处理 grep/glob其余工具零开销单次 stat每次校验最多一次statSync无额外系统调用绝对路径快速通道跳过拼接、直接返回确定性可注入pathOperations让测试无需真实文件系统也能覆盖平台差异生产中则使用 Node 原生路径实现与宿主完全一致。可观测性与无副作用承诺日志追踪阻断非法路径、透传 stat 错误、上报缺失路径时都会记录带上下文的日志条目工具名、原始路径、解析路径、错误码错误消息即指引两类错误文案都包含验证目标路径 / 列出父目录寻找正确位置 / 检查每个父组件是否为目录等可执行建议只拦截不改写钩子对有效路径不做任何修改唯一副作用是提前阻断无效调用因此对宿主行为是透明且安全的。总结从宿主报错到钩子指引的范式转变search-path-guard 的价值不在于发明新的搜索能力而在于把失败边界前移与其让 Agent 面对ripgrep execution failed这类无法归因的宿主错误不如在tool.execute.before阶段就用一次 stat 调用判断出路径不存在ENOENT还是路径结构非法ENOTDIR并分别给出可行动的修复指引对权限/IO 等不属于路径问题的错误则保持克制、原样透传。它与 absolute-path-rescue先改写猜测路径、tool-loop-guard后记录调用键的注册顺序以及 join/resolve 的宿主语义镜像共同构成了一个严谨、可测试、低开销的工具调用前校验层——任何在 OpenCode 生态中构建插件的开发者都可以把这套错误分类 语义镜像 注入式测试的方法论直接迁移到自己的钩子设计中。赞分享人工智能AI AgentAgent 编排AI 技能【免费下载链接】oh-my-opencode-slimLean, fine tuned Opencode multi agent suite · Mix any models · Auto delegate tasks项目地址https://gitcode.com/gh_mirrors/oh/oh-my-opencode-slim点击查看免费下载相关推荐oh-my-opencode-slim 的 Absolute Path Rescue HookAgent 绝对路径猜测错误的自动纠正机制oh my opencode slim 的 Absolute Path Rescue HookAgent 绝对路径猜测错误的自动纠正机制 导读 本篇文章围绕人工智能AI AgentAgent 编排AI 技能oh-my-opencode-slim 的 OpenCode Go 预设opencode-go preset将 Pantheon 多智能体迁往 OpenCode Go 模型oh my opencode slim 的 OpenCode Go 预设opencode go preset将 Pantheon 多智能体迁往 OpenC人工智能AI AgentAgent 编排AI 技能mise bootstrap dotfiles exclude用 glob 规则精准拦截 dotfile 捕获mise bootstrap dotfiles exclude用 glob 规则精准拦截 dotfile 捕获 mise bootstrap dotfiles开发工具CLI上一篇量化策略失效预警FinRL-Library漂移检测终极指南下一篇Local Deep Research v1.0 迁移指南用户认证、SQLCipher 加密数据库与 FastAPI 部署契约变更创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考