十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

oh-my-openagent 中 git-bash 组件剖析:Codex Windows 会话的 Git Bash MCP 引导钩子实现

oh-my-openagent 中 git-bash 组件剖析:Codex Windows 会话的 Git Bash MCP 引导钩子实现 oh-my-openagent 中 git-bash 组件剖析Codex Windows 会话的 Git Bash MCP 引导钩子实现【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent导读在 oh-my-openagentOmO的 Codex 插件体系中Windows 用户常常面临一个体验割裂问题Codex 内建exec_command与 OMO 提供的git_bashMCP 工具都能执行 shell 命令但两者在 Bash 语义、路径解析与命令回显上并不等价。packages/omo-codex/plugin/components/git-bash/AGENTS.md所描述的正是解决这一问题的关键组件一个在 Windows Codex 会话中通过PreToolUse钩子注入优先使用 git_bash MCP提示、并通过PostCompact钩子重置一次性标记的轻量级 Hook 包装器。阅读本文后你将掌握该组件的完整工作流会话级一次性提示、压缩后重置、Windows 环境容忍检测、永不阻塞 Bash 调用的失败语义理解它与git_bashMCP 服务、插件安装管线之间的协作关系并能在packages/omo-codex/plugin/components/git-bash/与packages/git-bash-mcp/源码中找到每一处实现的落点。组件定位不是 MCP而是引导 Agent 使用 MCP 的钩子首先需要澄清一个常见误解git-bash组件本身并不是 MCP 服务器而是一个引导者steering组件。它的职责是让 Windows 上的 Codex 会话在调用 Bash 类工具时优先选择 OMO 提供的git_bashMCP而不是 Codex 内建的exec_command。从 组件 AGENTS.md 的 OVERVIEW 可以看到真正的 MCP 服务由插件根目录的.mcp.json声明{ mcpServers: { grep_app: { url: https://mcp.grep.app }, context7: { url: https://mcp.context7.com/mcp }, git_bash: { command: node, args: [../../git-bash-mcp/dist/cli.js, mcp], cwd: . }, lsp: { command: node, args: [../../lsp-daemon/dist/cli.js, mcp], cwd: ., startup_timeout_sec: 10 } } }git_bash以 stdio 方式启动packages/git-bash-mcp/dist/cli.js mcp其实现位于packages/git-bash-mcp。该 MCP 层为 Codex 版本提供 Windows 专属的工具族工具作用平台约束which_bash解析bash.exe路径返回{found, path, source, candidates}跨平台diagnose报告 Git Bash 执行是否可用返回{platform, enabled, status, resolution}跨平台run通过bash.exe -lc执行命令参数含command必填、timeout≤30 分钟、workdir、description仅 Windows且仅在platform win32 canRunGitBash()时注册到tools/list而git-bash钩子组件sisyphuslabs/codex-git-bash-hook私有包bin 为omo-git-bash-hook则负责在会话层面提醒模型在 Windows 上执行 shell 命令时优先使用git_bashMCP仅在git_bash不可用或执行非 shell 操作时才回退到exec_command。在非 Windows 主机上该组件不产生任何输出Emits nothing on non-Windows hosts完全静默。文件结构与职责划分组件目录packages/omo-codex/plugin/components/git-bash/下的文件极少但分工清晰文件职责src/codex-hook.ts全部核心逻辑payload 解析与类型守卫、Windows 检测、提醒标记生命周期、Hook JSON 输出src/cli.tsBin 入口子命令hook pre-tool-use/hook post-compactstdin 输入 JSONstdout 输出 Hook JSONsrc/index.tscodex-hookAPI 的 barrel 导出hooks/hooks.jsonCodex 接线PreToolUse匹配器^Bash$PostCompact均调用node ${PLUGIN_ROOT}/dist/cli.js超时 5 秒test/codex-hook.test.ts7 个bun:test用例given/when/then 风格会话级一次性提醒、非 Bash / 非 Windows 跳过、PostCompact 重置、CLI 流式往返package.json包名sisyphuslabs/codex-git-bash-hook版本5.0.0-beta.79engines.node 20.0.0type: moduletsconfig.json严格 TS 配置strict、exactOptionalPropertyTypes、noUncheckedIndexedAccess等noEmit仅用于类型检查从 package.json 可以看到构建与测试约定scripts: { build: tsc -p tsconfig.build.json, test: bun test test/*.test.ts, typecheck: tsc --noEmit }, engines: { node: 20.0.0 }这里有一个值得注意的细节该组件运行时零依赖只依赖 Node 内置模块node:fs、node:os、node:path测试使用bun:test而非lsp组件所用的 vitest这也印证了 AGENTS.md 中Runtime dep-free Node 20 ESM与unlike the vitest-basedlspcomponent的说明。Codex Hook 接线hooks.json 与两个事件点hooks/hooks.json是组件与 Codex 运行时的契约完整内容如下{ hooks: { PreToolUse: [ { matcher: ^Bash$, hooks: [ { type: command, command: node \${PLUGIN_ROOT}/dist/cli.js\ hook pre-tool-use, timeout: 5, statusMessage: (OmO 5.0.0-beta.79) Recommending Git Bash MCP } ] } ], PostCompact: [ { hooks: [ { type: command, command: node \${PLUGIN_ROOT}/dist/cli.js\ hook post-compact, timeout: 5, statusMessage: (OmO 5.0.0-beta.79) Resetting Git Bash MCP Reminder } ] } ] } }两个事件点的分工PreToolUse匹配器^Bash$在模型请求调用名为Bash的工具之前触发。注意matcher是正则^Bash$因此仅精确匹配 Codex 内建的Bash工具不会拦截 MCP 工具如git_bash的run。每次会话第一次命中时钩子向会话注入一条additionalContext提醒。PostCompact在会话上下文压缩compaction完成后触发。它的作用是删除一次性提醒标记让下一次Bash调用能够再次注入提醒——因为压缩会截断上下文之前的提醒文本可能已被清除模型需要重新被告知。两个钩子都通过${PLUGIN_ROOT}环境变量定位组件安装根目录下的dist/cli.js并设置了 5 秒超时确保钩子开销可控。核心实现codex-hook.ts 的状态机src/codex-hook.ts是全部逻辑所在。整个流程可以概括为一个基于**标记文件marker file**的会话级状态机PreToolUse(Bash) 触发 ├─ hook_event_name 不是 PreToolUse → 静默 ├─ tool_name 不是 Bash → 静默 ├─ 不是 Windows 主机 → 静默 ├─ 已存在 session 标记文件 → 静默一次性 └─ 否则创建标记文件 输出 additionalContext 提醒 JSON PostCompact 触发 └─ 删除当前 session 的标记文件force→ 下一次 Bash 调用重新提醒1. Payload 解析与类型守卫Codex 以 JSON 形式把 Hook 事件写入 stdin。parsePreToolUsePayload与parsePostCompactPayload先做空输入检查raw.trim().length 0直接返回null再JSON.parse最后通过isPreToolUsePayload/isPostCompactPayload类型守卫逐字段校验。PreToolUsePayload接口要求的关键字段包括hook_event_name: PreToolUse、cwd、model、permission_mode、session_id、tool_name、tool_use_id、transcript_path可空、turn_id、tool_input任意值但必须存在该属性。PostCompactPayload则要求session_id为字符串transcript_path与trigger允许缺省或为 null。这种严格的字段校验保证了 Hook 收到畸形输入时不会误判。2. Windows 环境容忍检测isWindowsHost是组件的一个精巧设计它不只检查process.platform win32还同时检查环境变量OS Windows_NT、ComSpec是否存在、SystemRoot是否存在。这样做的原因是在 Windows 上通过 bash 宿主 shell 运行 Node 时process.platform可能并非win32但只要环境变量特征符合就仍然按 Windows 处理。实现中options.platform/options.env可被注入覆盖这正是测试用例能够模拟linux platform Windows env场景的原因。3. 会话级一次性提醒与标记路径提醒只在每个会话第一次 Bash 调用时注入一次。标记文件路径的计算逻辑为const root pluginDataRoot ?? process.env[PLUGIN_DATA] ?? join(homedir(), .codex, omo-git-bash); return join(root, git-bash-reminder, ${safePathSegment(sessionId)}.seen);即默认落在~/.codex/omo-git-bash/git-bash-reminder/session_id.seen可通过PLUGIN_DATA环境变量或pluginDataRoot选项覆盖。session_id会先经safePathSegment清洗把非[A-Za-z0-9._-]的字符替换为_避免路径注入。标记文件内容为一行 ISO 时间戳。注入的提醒文本REMINDER常量本身也值得细读On Windows, prefer the OMO git_bash MCP for shell commands before using built-in exec_command. Use exec_command only when git_bash is unavailable or for non-shell operations. In code mode, these tools may be deferred: inspect ALL_TOOLS with exec to discover the actual git_bash run, diagnose, and which_bash tool names, then invoke the matching entries through the tools object inside exec before treating git_bash as unavailable. Do not issue deferred names as top-level tool calls.这段提示不仅要求优先git_bash还特别处理了code mode 下工具延迟暴露deferred tools的情况提醒模型先通过exec检查ALL_TOOLS发现真实的run、diagnose、which_bash工具名再经tools对象间接调用而不是直接发起顶层工具调用。这是对 Agent 运行时工具发现机制的精确适配。4. 永不阻塞 Bash 调用组件最重要的健壮性约束是Hook 绝不能阻塞用户的 Bash 调用。runGitBashHookCli用 try/catch 包裹全部逻辑任何解析或文件系统错误都被吞掉并直接返回preToolUseOutput/postCompactOutput在 payload 为 null 时返回空字符串即使 stdin 为空或非法 JSON输出也是空。Codex 对 Hook 的约定是无输出即无干预因此失败路径等价于什么都没发生Bash 调用照常执行。5. CLI 入口src/cli.ts是一个极简的#!/usr/bin/env node脚本支持三个顶层用法Usage: omo-git-bash-hook hook pre-tool-use omo-git-bash-hook hook post-compact omo-git-bash-hook help | --help | -hhook pre-tool-use/hook post-compact分别把process.stdin/process.stdout交给runGitBashHookCli未知命令则写 stderr 并返回退出码 1。src/index.ts则把applyGitBashPreToolUseReminder、applyGitBashPostCompactReset、两个 parse 函数、runGitBashHookCli及全部相关类型导出供程序化复用。测试用例如何印证行为契约test/codex-hook.test.ts用 7 个bun:test用例把上述契约全部固化为可验证断言全部采用 given/when/then 命名用例验证点第一次 Windows Bash 调用输出hookSpecificOutput.hookEventName PreToolUseadditionalContext为字符串同一会话第二次 Bash 调用输出为空字符串标记生效一次性非 Windows Bash 调用输出为空字符串Windows 检测生效非 Bash 工具调用输出为空字符串matcher 之外的防御性校验PostCompact 重置第一次有提醒 → 第二次静默 → PostCompact 后第三次重新有提醒CLI pre-tool-use 流式往返从Readable喂 JSON捕获 stdout 并断言输出结构CLI post-compact 流式往返stdout 为空且后续 reminder 重新可触发测试中特别有意思的是Windows 模拟通过windowsEnv(){ OS: Windows_NT, ComSpec: C:\\Windows\\System32\\cmd.exe }加上platform: linux注入实现这正是对isWindowsHost环境容忍设计的直接验证而所有文件操作都落在mkdtempSync创建的临时目录测试后统一清理不污染真实用户数据目录。与插件安装管线的协作钩子组件的生效依赖 OMO 安装期管线把它正确部署进 Codex 插件缓存与配置。从组件 AGENTS.md 的 WHERE TO LOOK 可以定位到packages/omo-codex/src/install/下的三个关键文件codex-cache-bundled-mcps.ts把git-bash-mcp的 dist 拷贝进插件缓存并把.mcp.json中的参数改写为./components/git-bash-mcp/dist/cli.js。这解释了为什么插件根目录的.mcp.json写的是相对路径../../git-bash-mcp/dist/cli.js——发布部署时会经过改写。codex-config-plugins.ts仅在win32且成功解析到 Git Bash 时把[plugins.omosisyphuslabs.mcp_servers.git_bash]的enabled设为true其他平台设为false。这与 MCP 层run 工具仅 Windows 注册的约束形成双层保险。codex-git-bash-mcp-env.tsstampGitBashMcpEnv()在 win32 且设置了覆盖环境变量时把OMO_CODEX_GIT_BASH_PATH写入服务器env源码中GIT_BASH_ENV_KEY OMO_CODEX_GIT_BASH_PATH且仅在input.platform win32时执行用于显式指定 Git Bash 安装路径。此外packages/git-bash-mcp/AGENTS.md还补充了 MCP 层的超时环境变量链OMO_CODEX_GIT_BASH_TIMEOUT_MS→OMO_CODEX_EXEC_COMMAND_TIMEOUT_MS→CODEX_EXEC_COMMAND_TIMEOUT_MS→EXEC_COMMAND_TIMEOUT_MS→ 默认 120_000ms上限 30 分钟。这意味着从引导钩子到执行引擎整个 Windows Bash 体验是一条完整、可调的可观测链路。一个值得注意的兼容性细节Windows 绝对路径 MCP 目标AGENTS.md 的 NOTES 提到一次针对 Windows 路径的校验修复isPluginRuntimePathArg位于packages/omo-opencode/src/cli/doctor/checks/codex-components.ts与script/lazycodex-marketplace-validation.ts增加了isAbsolute(arg)判断从而让改写后的C:\...形式的 git_bash/lsp 入口路径能够通过校验。这意味着 OMO 在安装期把 MCP 参数从相对路径改写成 Windows 绝对路径后doctor 检查与 marketplace 验证不会误报失败——是安装管线 校验器配套演进的一个缩影。小结一次提醒背后的完整体系git-bash钩子组件虽然只有五个源文件却完整覆盖了一个生产级引导组件的所有要素明确边界它是提醒者而非执行者MCP 能力由packages/git-bash-mcp提供精准触发PreToolUse正则匹配^Bash$仅影响内建 Bash 工具调用会话级去重marker 文件 PostCompact重置既避免重复打扰又保证压缩后重新引导宽容的 Windows 检测platform 三组环境变量特征覆盖 bash 宿主 shell 场景零失败风险所有错误静默吞掉Hook 永不阻塞用户命令可测试、可部署7 个bun:test用例固化契约安装管线负责分发与按平台开关。对于在 Windows 上使用 OMO Codex 版本的开发者理解这个组件有助于排查为什么模型有时用 exec_command、有时用 git_bash的行为差异——答案就藏在~/.codex/omo-git-bash/git-bash-reminder/下的.seen标记文件以及hooks.json中那两条 5 秒超时的钩子声明里。【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表