ARTICLE DETAIL

资讯详情

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

Cline Hooks 测试夹具模板:为 Hooks 系统构建可复用的测试场景

Cline Hooks 测试夹具模板:为 Hooks 系统构建可复用的测试场景 Cline Hooks 测试夹具模板为 Hooks 系统构建可复用的测试场景【免费下载链接】clineAutonomous coding agent as an SDK, IDE extension, or CLI assistant.项目地址: https://gitcode.com/GitHub_Trending/cl/cline本文围绕 Cline VS Code 扩展中 Hooks 子系统的测试夹具fixture模板展开讲解如何基于 template 目录 提供的标准模板为 PreToolUse、TaskStart 等 Hook 类型编写、定制并注册新的测试场景。读完本文你将掌握 Hooks 测试夹具的目录约定、钩子脚本的输入/输出协议、跨平台Unix/Windows执行差异以及如何通过loadFixture()/withFixtureRunner()把新夹具接入 hook-factory.ts 的测试体系。模板定位Hooks 测试基础设施的起点Cline 的 Hooks 系统允许用户在工具调用前后、任务生命周期各阶段挂接自定义脚本。为了验证这一子系统的行为放行、拦截、上下文注入、报错仓库在apps/vscode/src/core/hooks/__tests__/fixtures/下维护了一整套预写的钩子脚本样本即测试夹具。fixtures 总目录的 README 将其组织为fixtures/ ├── hooks/ │ ├── pretooluse/ # PreToolUse 钩子夹具success / blocking / context-injection / error │ ├── posttooluse/ # PostToolUse 钩子夹具 │ ├── taskcancel/ taskcomplete/ taskresume/ taskstart/ userpromptsubmit/ ... └── template/ # 新夹具的模板目录模板目录 template 包含两个文件HookName —— 一个可直接执行的 Node.js 钩子脚本骨架内置从 stdin 读取 JSON 输入、按工具名分支注入上下文、以及 catch 兜底输出错误 JSON 的完整范式README.md —— 即本文所依据的模板说明文档给出创建新夹具的四步流程与最佳实践。新增夹具时的标准工作流是选定要覆盖的场景类型 → 从模板复制并改名 → 实现场景逻辑 → 更新 fixtures/README.md 的文档登记。四类基础场景先确定夹具要验证什么模板文档Step 1要求先明确新夹具测试的场景类型场景类型语义对应的输出约定success立即放行{ cancel: false, contextModification: ..., errorMessage: }blocking阻止工具/任务执行{ cancel: true, errorMessage: ... }context-injection向会话注入带类型前缀的上下文contextModification使用大写前缀如WORKSPACE_RULES:error以非零退出码终止向 stderr 输出错误并exit 1这些语义并非文档自说自话而是与运行时严格对齐的。以仓库中现存的 pretooluse/success 夹具 为例其全部实现就是#!/usr/bin/env node const input JSON.parse(require(fs).readFileSync(0, utf-8)); console.log(JSON.stringify({ cancel: false, contextModification: PreToolUse hook executed successfully, errorMessage: }));而 pretooluse/blocking 仅把cancel翻转为true、将拦截原因写入errorMessageTool execution blocked by hook。taskstart/blocking 遵循同样的两行差异模式说明场景差异最小化正是夹具设计的核心原则一个夹具只回答一个问题。输出字段的运行时约束模板脚本骨架中曾使用shouldContinue字段但需要注意当前运行时 hook-factory.ts 的validateHookOutput()会明确拒绝shouldContinue字段并提示迁移到cancel: true。因此编写新夹具时必须以现行协议为准cancel可选布尔true时请求取消任务/拦截执行contextModification可选字符串注入到会话上下文的文本超过 50KBMAX_CONTEXT_MODIFICATION_SIZE见 hook-factory.ts#L29会被截断并追加省略标记errorMessage可选字符串面向用户/日志的错误描述。运行时对退出行为还有额外规则直接影响error类夹具的编写非零退出且能解析出合法 JSON以 JSON 为准仅记录警告见 hook-factory.ts#L471-L481退出码 0 但无 JSON视为成功但不产生取消返回cancel: false非零退出且无合法 JSON抛出HookExecutionError.execution这正是error夹具要触发的路径输出中混有调试日志也没关系——运行时会从 stdout 末尾反向扫描括号提取最后一个完整 JSON 对象hook-factory.ts#L392-L462。模板脚本解剖stdin 输入协议HookName 模板 的核心是从 stdin 读 JSON、向 stdout 写 JSON的协议与HookProcess子进程执行方式一一对应。模板中各段的含义#!/usr/bin/env node try { // 1. 从 stdinfd 0读取并解析 Hook 输入 const input JSON.parse(require(fs).readFileSync(0, utf-8)); // 2. 按钩子类型解构业务字段 // PreToolUse: { toolName, parameters } const { toolName, parameters } input.preToolUse || {}; // PostToolUse 还可取 result, success, executionTimeMs // 3. 所有钩子类型共有的元数据 const { hookName: hookType, timestamp, taskId, workspaceRoots, userId } input; // 4. 输出变量三件套 let shouldContinue true; // 模板遗留写法新夹具应直接输出 cancel let contextModification ; let errorMessage ; // 5. CUSTOMIZE THIS LOGIC 自定义分支 if (toolName write_to_file) { contextModification FILE_OPERATIONS: File modification operation; } else if (toolName run_command) { contextModification SYSTEM_OPERATIONS: Command execution operation; } console.log(JSON.stringify({ shouldContinue, contextModification, errorMessage })); } catch (error) { // 6. 兜底把脚本自身异常包装为带 HOOK_ERROR 前缀的错误输出 console.log(JSON.stringify({ cancel: true, contextModification: , errorMessage: HOOK_ERROR: ${error instanceof Error ? error.message : String(error)} })); }其中第 3 步的元数据并非空谈——hook-factory.ts 的completeParams()会在序列化前自动补全clineVersion、hookName、timestamp、workspaceRoots、userId与modelprovider/slug夹具脚本因此始终能拿到稳定的公共上下文。第 6 步的 catch 兜底体现了模板的最佳实践之一钩子应自行优雅处理错误而不是裸抛异常后无输出。创建新夹具完整操作步骤Step 1创建目录结构按模板文档Step 2假设要新增一个 PreToolUse 校验场景mkdir -p apps/vscode/src/core/hooks/__tests__/fixtures/hooks/pretooluse/validation/ cp apps/vscode/src/core/hooks/__tests__/fixtures/template/HookName \ apps/vscode/src/core/hooks/__tests__/fixtures/hooks/pretooluse/validation/PreToolUse chmod x apps/vscode/src/core/hooks/__tests__/fixtures/hooks/pretooluse/validation/PreToolUse文件名必须与钩子类型严格同名PreToolUse、TaskStart等。这一点由发现逻辑保证findUnixHook() 在 Unix 上定位hooksDir/hookName并同时fs.statfs.access(X_OK)文件不存在或不可执行都会静默视为无钩子findWindowsHook() 在 Windows 上只认HookName.ps1无扩展名脚本被刻意忽略。Step 2实现场景逻辑模板文档Step 3给出的参数校验示例注意已将输出改为现行cancel协议#!/usr/bin/env node const input JSON.parse(require(fs).readFileSync(0, utf-8)); const { toolName, parameters } input.preToolUse; let cancel false; let contextModification ; let errorMessage ; // 自定义逻辑缺少 path 参数则拦截 if (!parameters || !parameters.path) { cancel true; errorMessage ERROR: Tool requires a path parameter; } else { contextModification VALIDATION: Basic input validation passed; } console.log(JSON.stringify({ cancel, contextModification, errorMessage }));Step 3登记到文档模板文档Step 4要求把新夹具补进 fixtures/README.md登记四要素夹具路径、返回值、用途、特殊行为备注。该 README 目前按钩子类型分节PreToolUse / PostToolUse / UserPromptSubmit / TaskStart …并给出每个夹具的精确返回对象例如hooks/pretooluse/context-injection返回{ cancel: false, contextModification: WORKSPACE_RULES: Tool [toolName] requires review }且动态引用输入中的工具名。跨平台执行夹具为什么看起来只是 Node 脚本模板文档Best Practices → Platform Compatibility强调夹具要写可移植的 Node.js 代码、避免平台特定逻辑因为这些夹具通过内嵌 shell 执行类似 git hooks。从源码看这一约束来自 test-utils.ts 的加载逻辑Unix/macOSloadFixture()直接复制文件并保留源文件的 mode 位fs.chmod(destFile, stats.mode)test-utils.ts#L601-L611这也是模板要求chmod x的原因Windows同名函数走 writeHookScriptForPlatform() 分支把 Node 脚本另存为HookName.js伴生文件并生成一个HookName.ps1PowerShell 桥接脚本把 stdin 直通给node退出码透传。buildPowerShellNodeBridge() 的注释还记录了历史坑早期[Console]::In.ReadToEnd() 管道的写法在 Windows CI 上与子进程退出竞态、偶发吞掉 stdout故改为让子进程直接继承父进程的管道。另外模板 README 引用的旧路径src/core/hooks/...是仓库重组前的写法当前实际路径为apps/vscode/src/core/hooks/__tests__/fixtures/...创建夹具时以后者为准。把夹具接进测试loadFixture 与 withFixtureRunner新夹具最终要服务于tests目录 下的各钩子类型测试。test-utils.ts 提供三层工具createHookTestEnv()建临时目录、在其下创建.clinerules/hookscreateHooksDirectory()test-utils.ts#L127-L131stub 掉getAllHooksDirs与 workspace 路径并重置 HookDiscoveryCachecleanup()负责还原 stub、清缓存与删除临时目录Windows 下对 EBUSY 锁有重试。loadFixture(fixtureName, destDir)把fixtures/fixtureName目录下的文件复制进destDir/.clinerules/hooks/如loadFixture(hooks/pretooluse/success, env.tempDir)。withFixtureRunner(hookName, fixtureName, callback)在独立环境中完成清目录 → 建 hooks 目录 → 重置发现缓存 → 加载夹具 →new HookFactory().create(hookName)全流程并保证清理避免多场景测试共享状态。fixtures/README.md 中的用法示例import { createHookTestEnv, loadFixture } from ../test-utils it(should work with real hook, async () { const env await createHookTestEnv() try { await loadFixture(hooks/pretooluse/success, env.tempDir) const factory new HookFactory() const runner await factory.create(PreToolUse) const result await runner.run(buildPreToolUseInput({ toolName: test_tool })) result.cancel.should.be.false } finally { await env.cleanup() } })输入构造器buildPreToolUseInput/buildPostToolUseInputtest-utils.ts#L321-L366生成的对象与运行时NamedHookInput类型一致——taskId 类型专属数据块。真实测试中的用法可参考 taskcancel.test.ts其中连续用loadFixture(hooks/taskcancel/false-no-error | true-with-error | ...)覆盖 TaskCancel 的四种返回组合验证cancel 标志 × 是否带错误消息的全真值表。命名与编写最佳实践模板文档Best Practices的三条规范结合仓库现状可以落到更可执行的程度单一场景一个夹具只验证一个行为逻辑保持简单上下文前缀大写contextModification使用WORKSPACE_RULES:、FILE_OPERATIONS:这类大写类型前缀便于在会话上下文中辨识来源现存夹具如 taskcancel/true-no-error 均遵循此约定平台可移植只用标准 Node API如fs.readFileSync(0)读 stdin不依赖 shell 特性。维护层面fixtures/README.md 的 Maintenance 节要求新增夹具必须同步登记文档废弃夹具连同引用一起移除——这与模板文档 Step 4 的更新文档要求首尾呼应保证夹具清单与实际目录长期一致。小结模板 README 看似简短实则是 Cline Hooks 测试体系的契约说明书它定义了场景四分法success / blocking / context-injection / error、stdin/stdout 的 JSON 协议、跨平台可移植性约束和文档登记流程。配合 hook-factory.ts 中的输出校验cancel协议、50KB 截断、非零退出与 JSON 优先规则和 test-utils.ts 中的环境/夹具加载工具链开发者可以按复制模板 → 改三处目录、逻辑、README 登记的固定成本为任意新钩子类型快速补充可回归、可复现的测试场景。【免费下载链接】clineAutonomous coding agent as an SDK, IDE extension, or CLI assistant.项目地址: https://gitcode.com/GitHub_Trending/cl/cline创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表