From 3fdf1e1843fcf26006755e44627848fa4adb0367 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Mon, 4 May 2026 11:49:48 -0700 Subject: [PATCH 1/3] [luv-282] chore: extend sync-hook-events prompt to all seven agent CLIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the Claude-only sync prompt with a multi-CLI version that diffs each agent CLI's hook event surface against its upstream docs (Claude, Codex, Copilot, Cursor, OpenCode, Pi, Gemini). Per-CLI diffs are emitted into .sync-hook-events-output.json under diffs., with `unverified: true` when docs can't be parsed (Pi is the likely candidate). Casing is preserved upstream-verbatim (PascalCase / snake_case / camelCase / dot.namespaced). Test-count fixups stay narrow: Claude in manager.test.ts and Gemini in integrations.test.ts. Other CLIs reference *HOOK_EVENT_TYPES.length directly. The agent intentionally does NOT add *EVENT_MAP entries for newly-added events — canonical mappings require human judgement, so CI is allowed to ship red on the first commit and the reviewer fixes the map before merge. Workflow changes: stage integrations.test.ts alongside the existing files, and broaden the commit message to "upstream agent CLI docs". --- .github/workflows/sync-hook-events.yml | 4 +- scripts/sync-hook-events-prompt.md | 217 +++++++++++++++++++------ 2 files changed, 170 insertions(+), 51 deletions(-) diff --git a/.github/workflows/sync-hook-events.yml b/.github/workflows/sync-hook-events.yml index a51bf1bc..e82d4b46 100644 --- a/.github/workflows/sync-hook-events.yml +++ b/.github/workflows/sync-hook-events.yml @@ -56,8 +56,8 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git checkout -b "$BRANCH" - git add src/hooks/types.ts __tests__/hooks/manager.test.ts - git commit -m "feat: sync hook event types with Claude Code docs" + git add src/hooks/types.ts __tests__/hooks/manager.test.ts __tests__/hooks/integrations.test.ts + git commit -m "feat: sync hook event types with upstream agent CLI docs" git push origin "$BRANCH" PR_TITLE=$(echo "$RESULT" | jq -r '.prTitle') diff --git a/scripts/sync-hook-events-prompt.md b/scripts/sync-hook-events-prompt.md index 04bdc0ea..f1c3c613 100644 --- a/scripts/sync-hook-events-prompt.md +++ b/scripts/sync-hook-events-prompt.md @@ -1,60 +1,179 @@ You are an automated agent running in GitHub Actions to keep failproofai's hook -event types in sync with the official Claude Code documentation. +event types in sync with the upstream documentation for **every** agent CLI we +integrate with. + +failproofai integrates with seven agent CLIs. Each one has its own hook event +surface, tracked as a separate `as const` array in `src/hooks/types.ts`: + +| CLI | Array constant | Casing convention | Has `*EVENT_MAP`? | +|----------------|-----------------------------|-------------------|--------------------| +| Claude Code | `HOOK_EVENT_TYPES` | PascalCase | no (canonical) | +| OpenAI Codex | `CODEX_HOOK_EVENT_TYPES` | snake_case | yes (`CODEX_EVENT_MAP`) | +| GitHub Copilot | `COPILOT_HOOK_EVENT_TYPES` | PascalCase | no | +| Cursor Agent | `CURSOR_HOOK_EVENT_TYPES` | camelCase | yes (`CURSOR_EVENT_MAP`) | +| OpenCode | `OPENCODE_HOOK_EVENT_TYPES` | dot.namespaced | yes (`OPENCODE_EVENT_MAP`) | +| Pi | `PI_HOOK_EVENT_TYPES` | snake_case | yes (`PI_EVENT_MAP`) | +| Gemini CLI | `GEMINI_HOOK_EVENT_TYPES` | PascalCase | yes (`GEMINI_EVENT_MAP`) | ## Your task -1. Fetch the Claude Code hooks reference pages using WebFetch: - - https://code.claude.com/docs/en/hooks (full reference — has the complete event table) - - https://code.claude.com/docs/en/hooks-guide (guide — also has a summary event table) - Extract the complete list of all hook event type names (e.g. SessionStart, - PreToolUse, PostToolUse, etc.) from the event lifecycle/trigger table. - Use both pages; union the results if they differ. Prefer the reference page. +### 1. Fetch upstream docs and extract the canonical event-name list per CLI + +| CLI | Docs URL(s) | +|-----------|------------------------------------------------------------------------------------| +| Claude | https://code.claude.com/docs/en/hooks (primary, full reference table) | +| | https://code.claude.com/docs/en/hooks-guide (secondary, summary table) | +| Codex | https://developers.openai.com/codex/hooks | +| Copilot | https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-hooks | +| Cursor | https://cursor.com/docs/hooks | +| OpenCode | https://opencode.ai/docs/plugins/ | +| Pi | https://www.npmjs.com/package/@mariozechner/pi-coding-agent | +| Gemini | https://geminicli.com/docs/hooks/ | + +For each CLI, use `WebFetch` on its docs URL(s) and extract the complete list of +hook event-type names from the lifecycle / triggers / "Available events" table +or section. Where two URLs are listed (Claude only), union the results and +prefer the reference page if they disagree. + +**Use the upstream casing exactly as it appears in the docs.** Do not normalize: +- Codex really is snake_case (`pre_tool_use`, `permission_request`, …). +- Cursor really is camelCase (`preToolUse`, `beforeSubmitPrompt`, …). +- OpenCode really is dot-namespaced (`tool.execute.before`, `session.idle`, …). +- Pi really is snake_case (`tool_call`, `user_bash`, `session_shutdown`, …). + +If a docs URL returns 404, redirects to a stub, or the page does not expose a +parseable event list, mark that CLI as `unverified` for this run and skip its +diff. **Do not invent events. Do not guess from prior knowledge.** Pi is the +most likely `unverified` candidate because its event surface is documented +primarily in the package source (`@mariozechner/pi-coding-agent` on npm), and +the README may not include a clean enumeration. + +### 2. Read the current array values + +Read `src/hooks/types.ts` and extract the current value of each +`*HOOK_EVENT_TYPES` array. + +### 3. Diff each verified CLI + +For every verified CLI, compute: +- **added**: events in upstream docs but NOT in the array +- **removed**: events in the array but NOT in upstream docs + +### 4. If no verified CLI has drift + +Write the following JSON to `.sync-hook-events-output.json` in the repo root: +```json +{ "changed": false } +``` +Then stop. (`unverified` alone is NOT drift — the docs may simply be unreachable +today.) + +### 5. If one or more verified CLIs have drift + +#### a. Update arrays in `src/hooks/types.ts` -2. Read `src/hooks/types.ts` and extract the current `HOOK_EVENT_TYPES` array - (the TypeScript `as const` array of strings). +For each CLI with drift: +- **Append additions** just before `] as const`, preserving casing. +- **Delete removals** from the array. If the CLI has an `*EVENT_MAP` (see the + table at the top), also delete the same key from that map block — TypeScript's + `Record` is exhaustive, and a stale key would + fail the build. -3. Diff the two lists: - - **added**: event types in the docs but NOT in our array - - **removed**: event types in our array but NOT in the docs +#### b. Update hardcoded test counts (only two CLIs need this) -4. If there are NO differences: - Write the following JSON to `.sync-hook-events-output.json` in the repo root: - ```json - { "changed": false } +Other CLIs reference `*HOOK_EVENT_TYPES.length` directly in tests, so no +hardcoded-count fixup is needed for them. + +- If `HOOK_EVENT_TYPES` (Claude) changed: in `__tests__/hooks/manager.test.ts`, + update the test description string `installs hooks for all event types` + AND both `expect(Object.keys(written.hooks)).toHaveLength()` assertions to + the new total. +- If `GEMINI_HOOK_EVENT_TYPES` changed: in `__tests__/hooks/integrations.test.ts`, + update the `expect(gemini.eventTypes).toHaveLength()` assertion AND the test + description string `writeHookEntries writes the matcher-wrapper schema for all + events with matcher='*'`. + +Locate these by searching for the current count number. + +#### c. Do NOT add `*EVENT_MAP` entries for newly-added events + +Each new agent-side event needs a canonical Claude PascalCase mapping that +requires human judgement (e.g. "is this a `PreToolUse`-class event? a +`SessionStart`? a passthrough no-op?"). For Codex, Cursor, OpenCode, Pi, and +Gemini drift, **leave the corresponding `*EVENT_MAP` untouched**. The +TypeScript build will fail with `Property '' is missing in type +Record<...>` and the ` keys exactly match` test will fail — both are +intentional and surfaced in the PR body. The reviewer adds the map entries, +pushes a fixup commit, and CI goes green before merge. + +For Claude and Copilot drift only, no event map exists — the build stays green +on the auto-commit alone. + +#### d. Do NOT touch `GEMINI_TOOL_MAP` + +That table maps Gemini's tool names (not event names) and is updated through +a different process. New tools surfaced by Gemini docs are out of scope for +this prompt. + +### 6. Write the structured output + +Write to `.sync-hook-events-output.json` in the repo root: +```json +{ + "changed": true, + "diffs": { + "claude": { "added": ["..."], "removed": ["..."] }, + "codex": { "added": [], "removed": [] }, + "copilot": { "added": [], "removed": [] }, + "cursor": { "added": ["..."], "removed": [] }, + "opencode": { "added": [], "removed": [] }, + "pi": { "unverified": true }, + "gemini": { "added": [], "removed": [] } + }, + "prTitle": "[auto] sync hook event types with upstream agent CLI docs", + "prBody": "" +} +``` + +Include a key for every CLI that was checked. Use `{"unverified": true}` (and +omit `added`/`removed`) for any CLI whose docs could not be parsed. + +The `prBody` MUST be a Markdown string containing, in order: + +1. **Summary table** — one row per CLI: + `| CLI | status | added | removed |` where status is one of + `up to date`, `drift`, or `unverified`. +2. **Per-CLI sections** — one section per CLI with non-empty drift, listing + added and removed events as bullet lists. +3. **Reviewer checklist** — for every newly-added event in a CLI that has an + `*EVENT_MAP`, an unchecked checkbox reminding the reviewer to add the + mapping. Use `"???"` as the canonical value placeholder; **do not guess**: + ``` + - [ ] Add `: "???"` to `` in `src/hooks/types.ts` + (canonical Claude `HookEventType` chosen by reviewer) ``` - Then stop. - -5. If there are differences: - - a. Update `HOOK_EVENT_TYPES` in `src/hooks/types.ts`: - - Add new event types (append after the last existing entry, before `] as const`) - - Remove stale event types if any - - b. Update `__tests__/hooks/manager.test.ts` — find the hardcoded event-type - counts and update them to the new total: - - The test description string matching `all N event types` - - The `toHaveLength(N)` assertion(s) that check `Object.keys(written.hooks)` - Search by the current count number to locate them. - - c. Write the following JSON to `.sync-hook-events-output.json` in the repo root: - ```json - { - "changed": true, - "added": ["EventA", "EventB"], - "removed": ["EventC"], - "prTitle": "[auto] sync hook event types with Claude Code docs", - "prBody": "..." - } - ``` - The `prBody` must be a Markdown string containing: - - List of **added** event types (or "none") - - List of **removed** event types (or "none") - - Source URLs used - - A note: "CI must pass and this PR must be reviewed before merging." +4. **Sources** — a list of the docs URL(s) consulted per CLI. +5. **Unverified notes** — for each `unverified` CLI, one short line explaining + why (404, page lacked a parseable event list, etc.). +6. **Final note** (verbatim): + > **CI is expected to fail on this PR if a CLI with an `*EVENT_MAP` gained + > new events. A reviewer must add the missing map entries before merging. + > For drift in Claude or Copilot only (no event map), CI should pass on + > this commit alone. CI must pass and this PR must be reviewed before + > merging.** ## Constraints -- **Only edit `src/hooks/types.ts`, `__tests__/hooks/manager.test.ts`, and - `.sync-hook-events-output.json`**. No other files. -- Do NOT run any shell commands (no git, no gh, no bun). -- Do NOT modify `policy-evaluator.ts`, `manager.ts`, or any other source file. +- **Only edit these files**: + - `src/hooks/types.ts` + - `__tests__/hooks/manager.test.ts` + - `__tests__/hooks/integrations.test.ts` + - `.sync-hook-events-output.json` +- Do NOT run any shell commands (no git, no gh, no bun, no curl). +- Do NOT modify `src/hooks/integrations.ts`, `src/hooks/policy-evaluator.ts`, + `src/hooks/manager.ts`, `src/hooks/handler.ts`, or any other source file. +- Do NOT add entries to any `*EVENT_MAP` or to `GEMINI_TOOL_MAP` for + newly-added events. Removing keys from a map when their array entry is + removed IS allowed (and required to keep the build green). +- Do NOT invent events. If WebFetch fails or the docs don't expose a clean + event list, mark the CLI `unverified` and move on. From 2ea802f89a7be415d8dde06425b54810690b4a06 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Mon, 4 May 2026 11:50:19 -0700 Subject: [PATCH 2/3] [luv-282] docs: changelog entry for multi-CLI sync-hook-events prompt --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4aaab8f..db7c3ab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - Auto-translated MDX: stop the recurring `mintlify validate` parse error in `docs/de/dashboard.mdx` (``) by adding a `sanitizeJsxAttributes` post-processor to the translation pipeline that strips stray ASCII `"` left after typographic-quote pairs (and any unmatched opening typographic quote) in JSX attribute values, and by tightening the translator system prompt to forbid ASCII `"` inside attribute values. Same regression PR #229 fixed by hand — now it can't recur. Includes the immediate file fix on `docs/de/dashboard.mdx`. (#247) ### Docs +- Extend the daily `sync-hook-events` GitHub Action prompt (`scripts/sync-hook-events-prompt.md`) from Claude-only to all seven integrated agent CLIs (Claude, Codex, Copilot, Cursor, OpenCode, Pi, Gemini). Each CLI's upstream docs URL is fetched, its hook event surface diffed against its `*HOOK_EVENT_TYPES` array in `src/hooks/types.ts`, and per-CLI drift surfaced under `diffs.` in `.sync-hook-events-output.json`. Casing is preserved upstream-verbatim (PascalCase / snake_case / camelCase / dot.namespaced). Test-count fixups stay narrow (Claude → `manager.test.ts`, Gemini → `integrations.test.ts`); the agent does NOT add `*EVENT_MAP` entries for newly-added events on Codex/Cursor/OpenCode/Pi/Gemini, since canonical mappings require human judgement — CI is allowed to ship red on the first commit and the reviewer fixes the map before merge. Workflow now stages `__tests__/hooks/integrations.test.ts` alongside the existing files (#282). - README: add Gemini CLI to the supported-CLIs intro line and visual list, with light/dark logo variants (`assets/logos/gemini-light.svg` + `gemini-dark.svg`). Restructure the logo block into two centred `

` rows (Claude/Codex/Copilot/Cursor on the first, OpenCode/Pi/Gemini on the second) plus a separate "+ more coming soon" line so the seventh logo doesn't crowd the layout. Update the beta callout to include Gemini CLI alongside Copilot, Cursor, OpenCode, and Pi (#277). - README: add Pi to the supported-CLIs intro line and visual list, with light/dark logo variants (`assets/logos/pi-light.svg` + `pi-dark.svg`); update beta callout to include Pi alongside Copilot and Cursor (#264). - README: add Cursor Agent to the supported-CLIs intro line and visual list, with light/dark logo variants (`assets/logos/cursor-light.svg` + `cursor-dark.svg`). Note that GitHub Copilot CLI testing is ongoing in the beta callout (#245). From 9e33b0f78c00d297b4c0413630deac99e4cf39e3 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Mon, 4 May 2026 11:55:17 -0700 Subject: [PATCH 3/3] [luv-282] docs: add language identifier to fenced code block (MD040) --- scripts/sync-hook-events-prompt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sync-hook-events-prompt.md b/scripts/sync-hook-events-prompt.md index f1c3c613..1318bb89 100644 --- a/scripts/sync-hook-events-prompt.md +++ b/scripts/sync-hook-events-prompt.md @@ -148,7 +148,7 @@ The `prBody` MUST be a Markdown string containing, in order: 3. **Reviewer checklist** — for every newly-added event in a CLI that has an `*EVENT_MAP`, an unchecked checkbox reminding the reviewer to add the mapping. Use `"???"` as the canonical value placeholder; **do not guess**: - ``` + ```text - [ ] Add `: "???"` to `` in `src/hooks/types.ts` (canonical Claude `HookEventType` chosen by reviewer) ```