From f3a90898730776b483f9d0d683b7522c1bfa2298 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Tue, 7 Apr 2026 20:38:36 +0000 Subject: [PATCH 1/3] feat: add 9 missing hook event types + daily sync workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add PermissionDenied, TaskCreated, StopFailure, InstructionsLoaded, CwdChanged, FileChanged, PostCompact, Elicitation, ElicitationResult to HOOK_EVENT_TYPES (17 → 26 total) - Update manager.test.ts counts accordingly - Add .github/workflows/sync-hook-events.yml: daily + manual job that runs Claude Code (sonnet) to fetch the Anthropic hooks docs, diff coverage, and auto-open a PR when new/removed events are detected - Add scripts/sync-hook-events-prompt.md: the checked-in prompt Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/sync-hook-events.yml | 38 +++++++++++++ __tests__/hooks/manager.test.ts | 6 +- scripts/sync-hook-events-prompt.md | 76 ++++++++++++++++++++++++++ src/hooks/types.ts | 13 ++++- 4 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/sync-hook-events.yml create mode 100644 scripts/sync-hook-events-prompt.md diff --git a/.github/workflows/sync-hook-events.yml b/.github/workflows/sync-hook-events.yml new file mode 100644 index 00000000..6b7d1ea2 --- /dev/null +++ b/.github/workflows/sync-hook-events.yml @@ -0,0 +1,38 @@ +name: Sync Hook Event Types + +on: + schedule: + - cron: '7 8 * * *' # daily at 08:07 UTC + workflow_dispatch: + +jobs: + sync-hooks: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - uses: actions/checkout@v4 + + - name: Set up git identity + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Install Claude Code CLI + run: npm install -g @anthropic-ai/claude-code + + - name: Run hook coverage sync + env: + ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }} + ANTHROPIC_AUTH_TOKEN: ${{ secrets.ANTHROPIC_AUTH_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FAILPROOFAI_TELEMETRY_DISABLED: "1" + CLAUDE_SKIP_SETUP_MODAL: "true" + run: | + claude \ + --model claude-sonnet-4-6 \ + --allowedTools "Read,Edit,Glob,Grep,WebFetch,Bash" \ + --dangerously-skip-permissions \ + -p "$(cat scripts/sync-hook-events-prompt.md)" diff --git a/__tests__/hooks/manager.test.ts b/__tests__/hooks/manager.test.ts index 24684361..9994241c 100644 --- a/__tests__/hooks/manager.test.ts +++ b/__tests__/hooks/manager.test.ts @@ -57,7 +57,7 @@ describe("hooks/manager", () => { }); describe("installHooks", () => { - it("installs hooks for all 17 event types into empty settings", async () => { + it("installs hooks for all 26 event types into empty settings", async () => { vi.mocked(existsSync).mockReturnValue(true); vi.mocked(readFileSync).mockReturnValue("{}"); @@ -69,7 +69,7 @@ describe("hooks/manager", () => { expect(path).toBe(USER_SETTINGS_PATH); const written = JSON.parse(content as string); - expect(Object.keys(written.hooks)).toHaveLength(17); + expect(Object.keys(written.hooks)).toHaveLength(26); for (const [eventType, matchers] of Object.entries(written.hooks)) { expect(matchers).toHaveLength(1); @@ -217,7 +217,7 @@ describe("hooks/manager", () => { expect(writeFileSync).toHaveBeenCalledOnce(); const [, content] = vi.mocked(writeFileSync).mock.calls[0]; const written = JSON.parse(content as string); - expect(Object.keys(written.hooks)).toHaveLength(17); + expect(Object.keys(written.hooks)).toHaveLength(26); }); it("uses 'where' on Windows and handles multi-line output", async () => { diff --git a/scripts/sync-hook-events-prompt.md b/scripts/sync-hook-events-prompt.md new file mode 100644 index 00000000..65f964be --- /dev/null +++ b/scripts/sync-hook-events-prompt.md @@ -0,0 +1,76 @@ +You are an automated agent running in GitHub Actions to keep failproofai's hook +event types in sync with the official Claude Code documentation. + +## 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. + +2. Read `src/hooks/types.ts` and extract the current `HOOK_EVENT_TYPES` array + (the TypeScript `as const` array of strings). + +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 + +4. If there are NO differences: print "Hook coverage is up to date. No changes needed." + and 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 two 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. Check whether a sync PR already exists to avoid duplicates: + ``` + gh pr list --base main --search "[auto] sync hook event types" --state open + ``` + If one is open, print "Sync PR already open. Skipping." and stop. + + d. Create a new branch: + ``` + git checkout -b auto/sync-hook-events-$(date +%Y%m%d) + ``` + + e. Stage only the two modified files: + ``` + git add src/hooks/types.ts __tests__/hooks/manager.test.ts + ``` + + f. Commit: + ``` + git commit -m "feat: sync hook event types with Claude Code docs" + ``` + + g. Push and open a PR: + ``` + git push origin auto/sync-hook-events-$(date +%Y%m%d) + gh pr create \ + --title "[auto] sync hook event types with Claude Code docs" \ + --body "..." \ + --base main + ``` + The PR body must include: + - 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." + +## Constraints + +- **Only edit `src/hooks/types.ts` and `__tests__/hooks/manager.test.ts`**. No other files. +- Do NOT run `bun install`, `bun test`, `bun build`, or any compile commands. +- Do NOT modify `policy-evaluator.ts`, `manager.ts`, or any other source file. +- git user identity is already configured by the workflow. +- `gh` is authenticated via `GH_TOKEN` in the environment. diff --git a/src/hooks/types.ts b/src/hooks/types.ts index 2c8e3351..9adbe409 100644 --- a/src/hooks/types.ts +++ b/src/hooks/types.ts @@ -10,19 +10,28 @@ export const HOOK_EVENT_TYPES = [ "SessionEnd", "UserPromptSubmit", "PreToolUse", + "PermissionRequest", + "PermissionDenied", "PostToolUse", "PostToolUseFailure", - "PermissionRequest", "Notification", "SubagentStart", "SubagentStop", + "TaskCreated", + "TaskCompleted", "Stop", + "StopFailure", "TeammateIdle", - "TaskCompleted", + "InstructionsLoaded", "ConfigChange", + "CwdChanged", + "FileChanged", "WorktreeCreate", "WorktreeRemove", "PreCompact", + "PostCompact", + "Elicitation", + "ElicitationResult", ] as const; export type HookEventType = (typeof HOOK_EVENT_TYPES)[number]; From 8843fd288be09f2205d7a2cecb34200e1831ecbd Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Tue, 7 Apr 2026 20:39:38 +0000 Subject: [PATCH 2/3] chore: bump version to 0.0.1-beta.12 Co-Authored-By: Claude Sonnet 4.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8e08969f..d059847d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "failproofai", - "version": "0.0.1-beta.11", + "version": "0.0.1-beta.12", "description": "Open-source hooks, policies, and project visualization for Claude Code & Agents SDK", "bin": { "failproofai": "./bin/failproofai.mjs" From 0ca1b9eb1acdf8b86f9438e08145b69189642c66 Mon Sep 17 00:00:00 2001 From: NiveditJain Date: Tue, 7 Apr 2026 20:46:20 +0000 Subject: [PATCH 3/3] fix: isolate GITHUB_TOKEN from Claude Code in sync workflow - Claude Code step now only receives ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN - Claude writes analysis result to .sync-hook-events-output.json (no Bash tool needed) - A separate shell step reads the output file and handles all git/gh operations - Add .sync-hook-events-output.json to .gitignore Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/sync-hook-events.yml | 47 +++++++++++++++++---- .gitignore | 3 ++ scripts/sync-hook-events-prompt.md | 58 ++++++++++---------------- 3 files changed, 63 insertions(+), 45 deletions(-) diff --git a/.github/workflows/sync-hook-events.yml b/.github/workflows/sync-hook-events.yml index 6b7d1ea2..bd2802fe 100644 --- a/.github/workflows/sync-hook-events.yml +++ b/.github/workflows/sync-hook-events.yml @@ -15,24 +15,55 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up git identity - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Install Claude Code CLI run: npm install -g @anthropic-ai/claude-code - - name: Run hook coverage sync + # Claude only gets its own API credentials — no GITHUB_TOKEN + - name: Analyze hook coverage and edit files env: ANTHROPIC_BASE_URL: ${{ secrets.ANTHROPIC_BASE_URL }} ANTHROPIC_AUTH_TOKEN: ${{ secrets.ANTHROPIC_AUTH_TOKEN }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} FAILPROOFAI_TELEMETRY_DISABLED: "1" CLAUDE_SKIP_SETUP_MODAL: "true" run: | claude \ --model claude-sonnet-4-6 \ - --allowedTools "Read,Edit,Glob,Grep,WebFetch,Bash" \ + --allowedTools "Read,Edit,Glob,Grep,WebFetch" \ --dangerously-skip-permissions \ -p "$(cat scripts/sync-hook-events-prompt.md)" + + # PR creation is handled here — GITHUB_TOKEN never touches Claude + - name: Create PR if changes detected + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + RESULT=$(cat .sync-hook-events-output.json 2>/dev/null || echo '{"changed":false}') + CHANGED=$(echo "$RESULT" | jq -r '.changed') + + if [ "$CHANGED" != "true" ]; then + echo "Hook coverage is up to date. No PR needed." + exit 0 + fi + + # Check for an existing open sync PR to avoid duplicates + EXISTING=$(gh pr list --base main --search "[auto] sync hook event types" --state open --json number --jq length) + if [ "$EXISTING" -gt 0 ]; then + echo "Sync PR already open. Skipping." + exit 0 + fi + + BRANCH="auto/sync-hook-events-$(date +%Y%m%d-%H%M)" + 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 push origin "$BRANCH" + + PR_TITLE=$(echo "$RESULT" | jq -r '.prTitle') + PR_BODY=$(echo "$RESULT" | jq -r '.prBody') + gh pr create \ + --title "$PR_TITLE" \ + --body "$PR_BODY" \ + --base main \ + --head "$BRANCH" diff --git a/.gitignore b/.gitignore index 42455312..c3df3a33 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,9 @@ next-env.d.ts # custom hooks loader temp files *.__failproofai_tmp__.* +# sync-hook-events workflow output (ephemeral, generated in CI) +.sync-hook-events-output.json + # package manager lockfiles (bun.lock is tracked; bun.lockb is binary) package-lock.json diff --git a/scripts/sync-hook-events-prompt.md b/scripts/sync-hook-events-prompt.md index 65f964be..04bdc0ea 100644 --- a/scripts/sync-hook-events-prompt.md +++ b/scripts/sync-hook-events-prompt.md @@ -17,8 +17,12 @@ event types in sync with the official Claude Code documentation. - **added**: event types in the docs but NOT in our array - **removed**: event types in our array but NOT in the docs -4. If there are NO differences: print "Hook coverage is up to date. No changes needed." - and stop. +4. If there are NO differences: + Write the following JSON to `.sync-hook-events-output.json` in the repo root: + ```json + { "changed": false } + ``` + Then stop. 5. If there are differences: @@ -26,42 +30,23 @@ event types in sync with the official Claude Code documentation. - 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 two hardcoded event-type + 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. Check whether a sync PR already exists to avoid duplicates: - ``` - gh pr list --base main --search "[auto] sync hook event types" --state open - ``` - If one is open, print "Sync PR already open. Skipping." and stop. - - d. Create a new branch: - ``` - git checkout -b auto/sync-hook-events-$(date +%Y%m%d) - ``` - - e. Stage only the two modified files: - ``` - git add src/hooks/types.ts __tests__/hooks/manager.test.ts - ``` - - f. Commit: - ``` - git commit -m "feat: sync hook event types with Claude Code docs" - ``` - - g. Push and open a PR: - ``` - git push origin auto/sync-hook-events-$(date +%Y%m%d) - gh pr create \ - --title "[auto] sync hook event types with Claude Code docs" \ - --body "..." \ - --base main - ``` - The PR body must include: + 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 @@ -69,8 +54,7 @@ event types in sync with the official Claude Code documentation. ## Constraints -- **Only edit `src/hooks/types.ts` and `__tests__/hooks/manager.test.ts`**. No other files. -- Do NOT run `bun install`, `bun test`, `bun build`, or any compile commands. +- **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. -- git user identity is already configured by the workflow. -- `gh` is authenticated via `GH_TOKEN` in the environment.