ECC 项目 C# Hook 自动化指南:用 dotnet format / build / test 守护 Agent 编辑质量
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
本文基于 ECC 仓库中 docs/ja-JP/rules/csharp/hooks.md(C# 专属 Hook 规则)展开,讲解在 Claude Code 等 Agent 环境中,如何为 C# 项目配置 PostToolUse 与 Stop 两类 Hook,让 Agent 每次编辑.cs文件后自动完成格式化、编译校验与测试回归,并在会话结束时兜底构建、拦截appsettings*.json中的密钥泄露。读完本文,你将掌握一套可直接复制到~/.claude/settings.json的 C# Hook 配置,并理解其底层执行机制。
一、先理解 ECC 的 Hook 系统骨架
C# Hook 规则是 ECC 通用 Hook 架构的扩展。通用规则定义在 rules/common/hooks.md,它把 Hook 划分为三种核心类型:
| Hook 类型 | 触发时机 | 能力 |
|---|---|---|
| PreToolUse | 工具执行之前 | 校验参数、拦截危险操作(可用退出码 2 阻止调用) |
| PostToolUse | 工具执行之后 | 自动格式化、运行检查(不可阻塞,只能分析输出) |
| Stop | 会话/响应结束时 | 最终验证、收尾检查 |
在 hooks/README.md 中,ECC 给出了完整的执行链路:
用户请求 → Agent 选择工具 → PreToolUse Hook 运行 → 工具执行 → PostToolUse Hook 运行 → Stop Hook 收尾C# 专属规则正是"PostToolUse 负责编辑后的即时质量闭环,Stop 负责会话结束时的最终兜底"这一思路在 .NET 生态中的落地。
二、C# Hook 的生效范围(paths 匹配规则)
docs/ja-JP/rules/csharp/hooks.md的 frontmatter 通过paths声明了本组规则匹配的 C# 相关文件类型:
paths: - "**/*.cs" # C# 源文件 - "**/*.csx" # C# 脚本 - "**/*.csproj" # 项目文件 - "**/*.sln" # 解决方案文件 - "**/Directory.Build.props" # MSBuild 全局属性 - "**/Directory.Build.targets" # MSBuild 全局目标这意味着格式化、编译校验等 Hook 应针对这些路径生效,涵盖源码(.cs)、脚本(.csx)、工程配置(.csproj/.sln)以及 MSBuild 的集中式构建定义文件(Directory.Build.props/.targets)。当 Agent 编辑这些文件时,PostToolUse Hook 才有必要触发dotnet相关命令;而编辑纯文档或前端代码时不应无谓地启动构建。
三、PostToolUse Hook:编辑后的即时质量闭环
C# 规则在 PostToolUse 阶段推荐三条命令,按"格式化 → 编译 → 测试"的顺序构成闭环:
| 命令 | 作用 |
|---|---|
dotnet format | 自动格式化被编辑的 C# 文件,并应用 analyzer(分析器)给出的修复 |
dotnet build | 验证编辑后解决方案或项目仍然可以编译 |
dotnet test --no-build | 行为发生变更后,重新运行最近的相关测试项目 |
为什么是这三条?
dotnet format对应"统一代码风格"。它不只做缩进排版,还会执行 Roslyn analyzer 的 code fix,把编辑过程中引入的风格违规就地修掉,避免 Agent 提交带警告的代码。dotnet build对应"编译正确性"。Agent 编辑.cs文件时常会改坏方法签名、漏掉引用,构建失败是最直接的红线。dotnet test --no-build对应"行为回归"。--no-build复用上一次构建产物,避免在测试阶段重复编译浪费时间;它只关心"改了行为之后,最近的测试项目是否还通过"。
三者配合的时序是:先格式化让代码可读,再编译确保语法与类型正确,最后跑测试确认行为未回归。这与 rules/common/hooks.md 中"PostToolUse 用于自动格式化与检查"的定位完全一致。
四、Stop Hook:会话结束时的最终兜底
C# 规则在 Stop 阶段给出两条收尾策略:
- 最终构建:在包含大量 C# 变更的会话结束前,执行一次
dotnet build,确保整个解决方案在会话收尾时处于可编译状态。因为 PostToolUse 只校验"单个编辑动作之后"的编译,而多次编辑叠加后可能引入跨文件的破坏,Stop 阶段的整体构建是对这一空白的补漏。 - 密钥泄露警告:对被修改的
appsettings*.json文件发出警告,防止密钥被提交进版本库。
第二条与 ECC 的 C# 安全规则 docs/ja-JP/rules/csharp/security.md 一脉相承——该规则明确要求:API 密钥、令牌、连接字符串绝不硬编码进源码;appsettings.*.json中不得包含真实凭据;本地开发应使用环境变量与用户机密(User Secrets),生产环境应使用密钥管理器:
// BAD const string ApiKey = "sk-live-123"; // GOOD var apiKey = builder.Configuration["OpenAI:ApiKey"] ?? throw new InvalidOperationException("OpenAI:ApiKey is not configured.");Stop Hook 对appsettings*.json的警告,正是把这条安全规则"机器化":即使 Agent 在配置文件中写了敏感信息,会话结束时也会被提示拦截在提交之前。
五、落地配置:可复制的 settings.json 示例
C# 规则明确配置位置为~/.claude/settings.json。参考仓库中 hooks/hooks.json 的 hook 条目结构(每条含matcher、type、command、description、id,支持async与timeout字段),C# 场景可按下述骨架配置:
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "dotnet format --include $(echo \"$INPUT\" | node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);console.log(i.tool_input?.file_path||'')})\")" } ], "description": "Auto-format edited C# files and apply analyzer fixes" }, { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "dotnet build", "timeout": 120 } ], "description": "Verify the solution still compiles after edits" }, { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "dotnet test --no-build", "timeout": 180 } ], "description": "Re-run nearest relevant test project after behavior changes" } ], "Stop": [ { "matcher": ".*", "hooks": [ { "type": "command", "command": "dotnet build", "timeout": 120 } ], "description": "Final build before ending a session with broad C# changes" }, { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "node -e \"let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{const i=JSON.parse(d);const p=i.tool_input?.file_path||'';if(/appsettings[^\\/]*\\.json$/.test(p)){console.error('[Hook] WARNING: modified appsettings*.json - verify no secrets will be committed')}console.log(d)})\"" } ], "description": "Warn on modified appsettings*.json files so secrets do not get committed" } ] } }几点实操提示:
matcher用于限定触发的工具类型:Edit|Write覆盖文件编辑场景;Stop阶段的最终构建可用.*匹配所有会话。timeout建议按命令耗时设置:dotnet format秒级,dotnet build一到两分钟,dotnet test --no-build视测试规模可给 3 分钟以上。dotnet format默认对整个解决方案生效,若只想格式化被编辑的单文件,可从 Hook 输入中读取tool_input.file_path传给--include(参见下文的 Hook 输入 Schema)。
六、底层机制:Hook 输入 Schema、退出码与异步执行
要让上面的配置真正可控,需要理解 ECC Hook 的运行时契约(见 hooks/README.md):
Hook 输入 Schema
每个 Hook 通过 stdin 接收 JSON,字段如下:
interface HookInput { tool_name: string; // "Bash", "Edit", "Write", "Read" 等 tool_input: { command?: string; // Bash:正在执行的命令 file_path?: string; // Edit/Write/Read:目标文件 old_string?: string; // Edit:被替换的文本 new_string?: string; // Edit:替换文本 content?: string; // Write:文件内容 }; tool_output?: { // 仅 PostToolUse 提供 output?: string; // 命令/工具输出 }; }这正是上一节中"从输入里取出file_path判断是否为appsettings*.json"这类逻辑的数据来源。
退出码约定
| 退出码 | 含义 |
|---|---|
0 | 成功,继续执行 |
2 | 阻止工具调用(仅 PreToolUse 有效) |
| 其他非零 | 出错,记录日志但不阻塞 |
因此dotnet build失败时 Hook 应以非零退出并输出到 stderr,让 Agent 看到错误;而"警告类"检查(如 TODO 提醒、密钥提示)只需向 stderr 打印提示并保持退出码 0。
异步 Hook
对于不应阻塞主流程的后台任务(例如构建产物分析),可以声明"async": true并设置timeout。异步 Hook 在后台运行,不能阻止工具执行,适合 C# 场景中"构建完成后做静态分析"这类锦上添花的检查。
七、运行时开关:用环境变量控制而不改配置
ECC 允许通过环境变量控制 Hook 行为(见 hooks/README.md),在排查 C# 构建 Hook 卡顿或临时跳过检查时非常有用:
# 总开关。显式设置的环境变量优先于插件偏好。 export ECC_HOOKS_ENABLED=true # minimal | standard | strict(默认 standard) export ECC_HOOK_PROFILE=standard # 按 hook id 精确禁用(逗号分隔) export ECC_DISABLED_HOOKS="pre:bash:tmux-reminder,post:edit:typecheck"其中 Hook Profile 的含义:
minimal— 仅保留必要生命周期与安全 Hook;standard— 默认档,均衡的质量与安全检查;strict— 启用更多提醒与更严格的护栏。
对 C# 团队而言,建议 CI/正式环境使用strict,让dotnet build/dotnet test --no-build的失败真正阻断流程;日常探索性编码可用standard或minimal减少干扰。
八、与 ECC 插件生态的关系
在 ECC 中,hooks/hooks.json 是完整的插件级 Hook 图谱(含 PreToolUse、PostToolUse、Stop、SessionStart、SessionEnd、PreCompact 等全部生命周期),且 hooks/README.md 特别提示:不要把仓库内的hooks.json原样粘贴到~/.claude/settings.json,而应通过 ECC 安装器完成部署,以保证命令按实际 Claude 根目录重写:
bash ./install.sh --target claude --modules hooks-runtime --enable-hooksWindows 下对应:
pwsh -File .\install.ps1 --target claude --modules hooks-runtime --enable-hooksC# 专属 Hook 规则(docs/ja-JP/rules/csharp/hooks.md)即属于这套体系中对特定语言生态的细化:它以通用 Hook 架构为骨架,把dotnet命令行工具链嵌入 Agent 的编辑生命周期,最终实现"Agent 改代码 → 自动格式化 → 自动编译 → 自动测试 → 会话收尾兜底 + 密钥防线"的完整自动化闭环。相关脚本实现可进一步在 scripts/hooks/ 目录中查阅。
【免费下载链接】ECCThe agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.项目地址: https://gitcode.com/GitHub_Trending/ev/ECC
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考