Skip to content

fix: git hooks self-heal when the init-time CLI shim breaks#89

Merged
wasabeef merged 2 commits into
mainfrom
fix/issue-88-hook-fallback
Jul 13, 2026
Merged

fix: git hooks self-heal when the init-time CLI shim breaks#89
wasabeef merged 2 commits into
mainfrom
fix/issue-88-hook-fallback

Conversation

@wasabeef

@wasabeef wasabeef commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Summary

All four fixes proposed in the issue, hardened for every install path (npx, bun, local node_modules, global, worktrees, bare repos, GUI git clients, husky/lefthook chains):

  • Success-gated fallback chain (pre-push, post-commit): a shim that exists but cannot start the CLI no longer consumes the attempt with exit 0 — the hook falls through to the common-dir shim, node_modules/.bin, and PATH. Gating is precise because the CLI deliberately exits zero for internal no-ops and failures (push-notes and record never propagate errors), so a non-zero exit means exactly "the CLI could not start".
  • Runtime-resolving shim: prefers the repository's current node_modules/.bin/agent-note, then a PATH install, and keeps the init-time absolute paths as the last resort. The command -v node gate and the retained baked paths protect restricted hook environments (GUI git clients without the user's PATH) that today rely on the absolute node path — no regression for those users.
  • Visible degradation: when no resolver can start the CLI, hooks emit a one-line stderr warning and still exit zero. The pre-push warning is additionally gated on a local refs/notes/agentnote ref so checkouts that never use Agent Note stay quiet, and the post-commit warning is deduplicated across the trailer and env-fallback record attempts.
  • PR report detection line: the action emits a ::notice (not warning, since human-only PRs legitimately have no tracked data) when a PR has commits but zero tracked commits.

The contradictory hook comments ("exact CLI version that generated these hooks" vs "tracks the current CLI implementation after upgrades") are unified on the latter, which the shim now actually implements.

prepare-commit-msg is untouched — it never invokes the CLI, so the issue's mention of it did not apply.

Root cause

installLocalCliShim baked process.execPath and resolve(process.argv[1]) at init time. Deleting the checkout that ran init (worktree flows), upgrading node (mise/nvm), or pruning the npx cache left a broken-but-executable shim; the hooks' -x test passed, || true swallowed the failure, and an unconditional exit 0 prevented the remaining resolvers from running. Notes silently stopped recording and pushing while git kept succeeding.

User impact

Checkouts with any working CLI install self-heal immediately with the new hooks. Environments with no working install now see a one-line stderr warning instead of silent data loss, and PR reports flag suspicious zero-tracked results. Commits and pushes are never blocked. Existing repositories pick up the fix by re-running npx agent-note init (managed hooks and the shim are upgraded in place).

Validation

  • CLI: build, typecheck, lint, 495 tests passed — including 4 new regression tests: broken shim + node_modules fallback records the commit note; broken shim + fallback pushes notes to the remote; push with no usable resolver emits the warning once while the main push succeeds; commit with no usable resolver emits the warning exactly once and writes no note
  • pr-report: ncc build, 51 tests passed
  • Existing worktree/bare-repo/hooksPath/chained-hook suites all pass unchanged

Closes #88

🧑💬🤖 Agent Note

Total AI Ratio: ████████ 100%
Model: claude-fable-5

Commit AI Ratio Prompts Files
c191b04 fix(init): self-heal git hooks when the init-time CLI shim breaks █████ 100% 1 CLAUDE.md 🤖, architecture.md 🤖, cli.js 👤, init.test.ts 🤖, init.ts 🤖, index.js 👤, index.ts 🤖
9febe29 fix(init): let the shim fall through to init-time paths on runtime failures █████ 100% 2 cli.js 👤, init.test.ts 🤖, init.ts 🤖, index.js 👤, github.ts 🤖, index.test.ts 🤖, index.ts 🤖
💬 Prompts & Responses (2 shown / 3 total)

c191b04 fix(init): self-heal git hooks when the init-time CLI shim breaks

🧑 Prompt

これは、利用者側の問題でなければ全部対応するべき

9febe29 fix(init): let the shim fall through to init-time paths on runtime failures

🧑 Prompt

#89 (comment)

も確認

Summary by CodeRabbit

  • Bug Fixes

    • Git hooks now recover from stale or unavailable CLI paths by trying alternative locations.
    • Commits and pushes are no longer blocked when the CLI cannot start.
    • Added concise warnings when notes cannot be recorded or pushed.
  • Improvements

    • Pull request reports now notify you when tracked commit data is unavailable and recommend re-running initialization.
  • Documentation

    • Updated guidance on CLI resolution, hook fallback behavior, and failure handling.

Why
The repo-local shim baked the node binary and CLI entry paths captured
at init time. When the checkout that ran init was deleted or the node
version changed, the shim kept existing and stayed executable, so the
hook fallback chain short-circuited on it, swallowed the failure, and
notes silently stopped being recorded and pushed while git kept
succeeding.

The shim now resolves the repository's current CLI install at runtime
(node_modules, then PATH) and keeps the init-time paths only as the
last resort for restricted hook environments such as GUI git clients.
Hook scripts gate each resolver on success — the CLI exits zero even
for internal no-ops and failures, so a non-zero exit precisely means
the CLI could not start — and fall through instead of stopping. When
no resolver can run the CLI, the hooks emit a one-line stderr warning
while still exiting zero, and the PR report action emits a notice when
a PR has commits but no tracked data.

User impact
Deleting the worktree that ran init, upgrading node, or pruning the
npx cache no longer silently disables Agent Note in checkouts that
have a local or global CLI install, and the remaining failure modes
are visible instead of silent. Commits and pushes are never blocked.
Existing repositories pick up the new hooks and shim by re-running
agent-note init.

Verification
npm -w packages/cli run build
npm -w packages/cli run typecheck
npm -w packages/cli run lint
npm -w packages/cli test (495 passed, 4 new hook fallback tests)
npm -w packages/pr-report run build
npm -w packages/pr-report test (51 passed)

Release note: Git hooks now recover automatically when the repo-local CLI shim breaks, and failures emit a visible warning instead of silently skipping Agent Note recording.

Agentnote-Session: 4a6d322d-5afe-45e3-a11b-cf15d0e740a9
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Git hook and reporting resilience

Layer / File(s) Summary
Runtime CLI shim resolution
packages/cli/src/commands/init.ts, packages/cli/src/commands/init.test.ts
The generated shim resolves the repository-local CLI at runtime, falls back to PATH, and has expanded fallback-chain assertions.
Hook resolver chains and regression coverage
packages/cli/src/commands/init.ts, packages/cli/src/commands/init.test.ts
Post-commit and pre-push hooks try multiple CLI locations, warn when none work, and continue allowing commits and pushes.
Repair notice and behavior documentation
packages/pr-report/src/index.ts, docs/architecture.md, CLAUDE.md
PR reports notify when tracked commit data is missing, while documentation describes shim resolution and hook failure handling.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Git
  participant Hook
  participant AgentNoteShim
  participant AgentNoteCli
  participant GitNotes
  Git->>Hook: run post-commit or pre-push hook
  Hook->>AgentNoteShim: try repo-local shim
  AgentNoteShim->>AgentNoteCli: resolve current CLI or PATH CLI
  AgentNoteCli->>GitNotes: record or push notes
  Hook-->>Git: warn and exit zero if no resolver works
Loading

Possibly related issues

Possibly related PRs

  • wasabeef/AgentNote#77 — Directly overlaps with generated hook fallback chains and git-directory shim resolution.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: git hooks now recover when the init-time CLI shim breaks.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/issue-88-hook-fallback

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/pr-report/src/index.ts`:
- Around line 261-268: Add tests in index.test.ts covering the report flow
around shouldRetryNotesFetch: assert that after retries, a report with
total_commits > 0 and tracked_commits === 0 emits the repair message through
core.notice, and assert that a null report returns early without triggering the
notice path. Reuse existing test setup and mocks for the index entry point.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e0ebede4-7ec6-4c9e-803b-736f5a16b38e

📥 Commits

Reviewing files that changed from the base of the PR and between d6c7537 and c191b04.

⛔ Files ignored due to path filters (2)
  • packages/cli/dist/cli.js is excluded by !**/dist/**, !**/dist/**
  • packages/pr-report/dist/index.js is excluded by !**/dist/**, !**/dist/**
📒 Files selected for processing (5)
  • CLAUDE.md
  • docs/architecture.md
  • packages/cli/src/commands/init.test.ts
  • packages/cli/src/commands/init.ts
  • packages/pr-report/src/index.ts

Comment thread packages/pr-report/src/index.ts Outdated
…ilures

Run the shim's node_modules and PATH resolvers without exec so a CLI
launch that fails at runtime (for example an incompatible node found on
a restricted PATH) still reaches the init-time absolute paths instead
of consuming the attempt. Also assert in tests that the pre-push
warning fires only when notes really were not pushed, and extract the
PR report repair notice into buildMissingNotesNotice with unit tests.
Addresses self-review and CodeRabbit feedback on PR #89.

Release note: skip

Agentnote-Session: 4a6d322d-5afe-45e3-a11b-cf15d0e740a9
@wasabeef wasabeef merged commit f90aac5 into main Jul 13, 2026
11 checks passed
@wasabeef wasabeef deleted the fix/issue-88-hook-fallback branch July 13, 2026 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: hooks silently stop pushing/recording notes when the init-time CLI shim breaks (baked absolute paths + fallback chain short-circuit)

1 participant