Skip to content

fix: install/uninstall-hooks merge per event, keep foreign hooks (GIT-120) - #55

Merged
1 commit merged into
mainfrom
bugfix/GIT-120-hooks-merge
Sep 23, 2026
Merged

1 commit merged into
mainfrom
bugfix/GIT-120-hooks-merge

Conversation

@nTEG-dev

Copy link
Copy Markdown
Member

GIT-120: install-hooks and uninstall-hooks keep foreign hooks

Just upgrade the package. Nothing to change on your database. No store involvement.

What was wrong

  • install-hooks replaced settings.hooks wholesale, and uninstall-hooks deleted the key. Every hook a user or another tool had configured was lost.
  • "Already installed" was detected by any gitmem substring. A foreign hook such as bash ~/code/gitmem-notes/lint.sh made main skip the install entirely.
  • An unparseable settings.json was replaced with a fresh file.
  • Cursor's install-hooks also replaced hooks wholesale.

Fix (bin/hooks-merge.js, used by bin/gitmem.js)

  • Merge per event and per command. Only commands gitmem installed are replaced or removed. A matcher group keeps its other commands. Events install-hooks does not manage stay untouched, including the UserPromptSubmit hook that gitmem init installs.
  • gitmem commands are recognised by gitmem's script paths (.gitmem/hooks/*.sh, gitmem-mcp/hooks/scripts/*.sh, legacy gitmem-hooks).
  • The file is backed up to <file>.gitmem-backup-<timestamp> before each write. The output lists the change per event and the backup path.
  • An unparseable file, or a hooks value of the wrong shape, exits 1 with "Nothing was changed".
  • Applies to Claude Code .claude/settings.json and Cursor .cursor/hooks.json.

Evidence

New CLI e2e tests/e2e/git-120-hooks-merge.test.ts runs the real CLI in a scratch repo with foreign hooks. It is wired into CI next to the GIT-89 step.

  • Branch: 9/9 pass.
  • Main: 6 of the first 8 fail (the 9th, init's auto-retrieve hook, was added afterwards):
× install-hooks keeps foreign hooks, backs up first, and prints what changed   (main: "already installed", 0 gitmem hooks)
× install-hooks --force twice replaces gitmem's hooks without duplicating them
× uninstall-hooks removes only gitmem's commands ...                            (main: hooks undefined)
× uninstall-hooks keeps a foreign command that shares a matcher group
× an unparseable settings.json is not overwritten                              (main: exit 0, file replaced)
× install and uninstall keep a foreign Cursor hook

tsc clean. Unit 1357, unchanged.

Old-behaviour tests changed

tests/e2e/cli-fresh-install.test.ts pinned the wipe:

  • "install-hooks --force preserves permissions" now also expects the fixture's foreign echo old hook to survive.
  • "uninstall-hooks removes hooks from settings" expected hooks undefined. It now expects only echo old to remain.
  • "uninstall-hooks is idempotent" now expects "No gitmem hooks found".

Two other tests in that file fail on main and on this branch alike: "gitmem init creates .gitmem/ with starter scars" and "session-close-check.sh ceremony wording". That file is not in CI yet; wiring it is part of GIT-115.

Not changed, flagged

  • bin/init-wizard.js and bin/uninstall.js still match hooks by a bare gitmem substring and drop whole matcher groups. That can remove a foreign command that shares a group. They are left for GIT-115, which reworks the wizard.
  • install-hooks installs no UserPromptSubmit hook, but gitmem init does. The two hook sets differ.
  • uninstall-hooks still clears /tmp/gitmem-hooks-* machine-wide. That is existing behaviour, and the e2e exercises it.

🤖 Generated with Claude Code

…ooks (GIT-120)

install-hooks replaced settings.hooks wholesale and uninstall-hooks deleted
the key, so users' own hooks were lost. Both now work per event and per
command: only commands gitmem installed are replaced or removed, a matcher
group keeps its other commands, events install-hooks does not manage stay
untouched, the file is backed up before every write, and the output lists
what changed. An unparseable file is no longer overwritten "fresh".

gitmem detection matches gitmem's script paths instead of any "gitmem"
substring, which made a foreign hook under a gitmem-named directory look
like an existing install.

Tests: new CLI e2e (9) with foreign hooks present, wired into CI. Two
cli-fresh-install assertions that pinned the old wipe are updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@nTEG-dev nTEG-dev closed this pull request by merging all changes into main in 60a990e Sep 23, 2026
@nTEG-dev
nTEG-dev deleted the bugfix/GIT-120-hooks-merge branch September 23, 2026 05:34
neoneye pushed a commit to agent-memory-atlas-archive/gitmem-dev--gitmem that referenced this pull request Sep 24, 2026
…ig + hooks (GIT-115)

init seeded <cwd>/.gitmem while the server reads ~/.gitmem (GIT-91), so a
fresh install had no starter lessons and was told its store was "NOT being
read". The wizard and init-scars now seed learnings, threads, collections
and the closing payload + template into the root the server reads
(GITMEM_DIR, then GITMEM_HOME/.gitmem, then ~/.gitmem). The repo's .gitmem/
keeps only config.json (project name) and the hook scripts.

- A repo .gitmem/ with only config.json and hooks, or only what an older init
  seeded, is not a stranded store. Real records (a user's learning, thread or
  decision) now count, which main did not check at all.
- The SessionStart hook reads the repo's project name without jq (node).
- uninstall removes the repo's config.json and hooks; the shared store is
  kept unless --all or the user says delete. Hook removal and the wizard's
  hook merge use the GIT-120 module (bin/hooks-merge.js, identical to gitmem-dev#55).
- telemetry commands use the server's root.

Tests: fresh-install e2e in a clean HOME (9, all fail on main), unit +5,
hook suite +1. cli-fresh-install made hermetic (scratch HOME) and repaired;
both e2e files wired into CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant