Skip to main content

coding-agents-hooks-authoring

To author, register, and test Rosetta hooks, add a SemanticKind, or debug a hook that won't fire.

소스 정보

저장소
griddynamics/rosetta
최근 소스 활동
2026년 9월 15일 01:56
감지된 SKILL.md 언어
영어
스타
354
포크
79

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
coding-agents-hooks-authoring
description
To author, register, and test Rosetta hooks, add a SemanticKind, or debug a hook that won't fire.
<hooks_authoring> ### Hook entry rule Only files that export `defineHook(…)` AND call `runAsCli(hook, module)` belong directly in `src/hooks/src/hooks/`. Every `.ts` at the top level of that directory becomes a standalone CJS bundle distributed to all 6 IDE targets (claude-code, codex, copilot, cursor, windsurf, antigravity). Helper/data files without `runAsCli` belong in a named subdirectory: `src/hooks/src/hooks/<feature>/`. ### Helper placement - Feature-local helpers → `src/hooks/src/hooks/<feature>/` (e.g. `src/hooks/src/hooks/dangerous-actions/patterns.ts`). - Cross-hook runtime helpers → `src/hooks/src/runtime/`. ### Build is non-recursive `src/hooks/scripts/build-bundles.mjs:29` uses `readdirSync(hooksDir).filter(f => f.endsWith('.ts'))`. There is **no `{ recursive: true }`**. Subdirectories are invisible to the bundler. Adding a top-level `.ts` without `runAsCli` produces a dead bundle for every plugin. A plugin may opt a hook OUT via `excludeHooks` in the `PLUGINS` array (`build-bundles.mjs`) — e.g. `core-antigravity` excludes the advise-only hooks, which have no delivery channel there. ### Adding a SemanticKind When a hook needs a new tool category (e.g. `mcp-call`): 1. **`src/hooks/src/runtime/ide-registry.ts`** — add a row to `TOOL_KINDS` with all 6 IDE columns (`null` where the event doesn't exist). `SemanticKind = keyof typeof TOOL_KINDS` so TypeScript enforces coverage. 2. **`src/hooks/src/runtime/ide-rows/<ide>.ts`** — if the kind requires special logic (e.g. prefix-match for `mcp__.*`), add a conditional branch at the top of `lookupToolKind` in the IDE-row file before the table loop. Table-driven lookup alone cannot handle open-ended tool name patterns. 3. **Hook entry** — add the new kind to `def.on.toolKinds`. 4. **Matcher in `hooks.json.tmpl`** — widen to include new tool names/patterns. Order matters: `run-hook.ts:316` gates on `toolKinds` before calling `def.run(ctx)`. Matcher passes the event in; `toolKinds` must include the mapped kind or the call is dropped silently. ### Registration Every new hook must appear in each registering plugin's `hooks.json`. The canonical sources are the `hooks.json.tmpl` templates; direct edits to generated `hooks.json` files are overwritten on the next `npx rosettify-plugins` run. Template paths by plugin, all under `src/rosettify-plugins/plugins/` (templates are generator input only — `.tmpl` files are not emitted into the generated `plugins/` tree): - `core-claude/hooks/hooks.json.tmpl` - `core-codex/.codex-plugin/hooks.json.tmpl` - `core-copilot/hooks/hooks.json.tmpl` (+ `core-copilot/.github/plugin/hooks.json.tmpl`) - `core-cursor/hooks.json.tmpl` (+ `core-cursor/hooks/hooks.json.tmpl`) - `core-antigravity/hooks.json.tmpl` - `core-windsurf` is a `build-bundles.mjs` `PLUGINS` bundle target but has no plugin directory / `hooks.json` registration yet. ### Platform-scoped events `PreToolUse` is absent on Copilot (`'copilot': null` in `ide-registry.ts`). If a hook uses a platform-exclusive event, add its name to `CLAUDE_CODE_ONLY_HOOKS` Set in `src/hooks/tests/regression/hooks-registered.test.ts`. Before adding a second scoped hook, refactor the Set to `Map<string, Set<IdeName>>`. ### Tests Co-locate tests in `src/hooks/tests/<hook-name>.test.ts`. The regression test (`src/hooks/tests/regression/hooks-registered.test.ts`) automatically discovers all `.ts` entries at `src/hooks/src/hooks/` top level and asserts each is referenced in every plugin's `hooks.json`. A new hook without registration immediately fails the regression guard. ### Sync command After any source change under `src/hooks/src/` or `instructions/r{2,3}/core/`: ```bash venv/bin/python scripts/pre_commit.py ``` This builds CJS bundles, runs full test suite, and runs `npx rosettify-plugins` to sync `instructions/r{2,3}/core/` → all plugin directories. ### Pitfalls - **Helper files in top-level** — produces dead bundles for every plugin + false regression test failures without `isLibraryModule` workaround. Fix: move to subdirectory. - **Missing registration** — hook fires silently nowhere; regression test catches this at CI time. - **Secrets in Evidence** — `buildDenyMessage` echoes `evidence` to transcript by default. Pass `redact=true` for DANGEROUS_CONTENT matches (AWS keys, PEM certs, SQL with row data). - **Regex `[rf]{2,}` false positives** — matches `rm -rr` and `rm -ff`. Require both flags with lookaheads: `/\brm\s+-(?=[a-zA-Z]*[rR])(?=[a-zA-Z]*[fF])[a-zA-Z]+\b/`. - **`$`-anchor vs trailing slash** — path patterns like `/\.kube\/config$` fail when tested against `filePath` with trailing slash. Always test against `normalizedPath = filePath.replace(/\/+$/, '')`. - **Matcher without toolKinds mapping** — adding a name to the JSON matcher but not to `lookupToolKind` and `def.on.toolKinds` is inert. - Updating instructions/* and plugins/* which serve completely different purpose. ### Reference files ``` src/hooks/scripts/build-bundles.mjs src/hooks/src/runtime/ide-registry.ts src/hooks/src/runtime/ide-rows/claude-code.ts src/hooks/src/runtime/run-hook.ts:316 plugins/core-claude/hooks/hooks.json.tmpl src/hooks/tests/regression/hooks-registered.test.ts ``` </hooks_authoring>
GitHub에서 보기