Skip to content

refactor: introduce agent hook installer#318

Open
tumberger wants to merge 1 commit into
mainfrom
refactor/agent-hook-installer
Open

refactor: introduce agent hook installer#318
tumberger wants to merge 1 commit into
mainfrom
refactor/agent-hook-installer

Conversation

@tumberger

@tumberger tumberger commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add shared hook merge/remove and JSON file helpers for agent integrations.
  • Migrate Claude user hook settings onto the shared helpers without behavior changes.

Verification

  • go test ./...

tumberger commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

@tumberger tumberger force-pushed the refactor/agent-hook-installer branch 5 times, most recently from 35c5022 to 4fef034 Compare June 24, 2026 13:11
@tumberger tumberger marked this pull request as ready for review June 24, 2026 13:41
@greptile-apps

greptile-apps Bot commented Jun 24, 2026

Copy link
Copy Markdown

Greptile Summary

This PR moves Claude hook installation onto a shared agent hook helper. The main changes are:

  • New shared command parsing and command handler types.
  • New generic hook config merge, remove, and lookup helpers.
  • New typed hook plans for canonical handler generation.
  • Claude user settings now use the shared helpers for merge and uninstall.
  • Tests cover parsing, preservation, pruning, idempotency, and template shape.

Confidence Score: 5/5

This looks safe to merge, with one small compatibility edge case to consider.

  • No blocking issues found in the changed code.
  • The shared merge and remove paths preserve the existing command-only managed hook shape.
  • A split command-plus-args encoding can be missed by the Claude ownership predicates.

internal/claudemanaged/usersettings.go

Important Files Changed

Filename Overview
internal/agenthooks/command.go Adds shared command handler parsing and shell-like command splitting for hook ownership checks.
internal/agenthooks/config.go Adds shared JSON hook map helpers for preserving foreign content while merging or removing owned handlers.
internal/agenthooks/plan.go Adds typed hook plans and canonical native group generation for supported hook events.
internal/claudemanaged/settings.go Switches managed settings detection to the shared command splitter.
internal/claudemanaged/usersettings.go Migrates Claude user settings merge and removal to the shared hook config and plan helpers.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Claude settings map] --> B[MergeManagedHooks or RemoveManagedHooks]
  B --> C[managedHookPlan]
  C --> D[agenthooks.Plan]
  B --> E[agenthooks.Config]
  E --> F[HooksMap]
  E --> G[withoutOwnedHandlers]
  G --> H[CommandHandler predicates]
  H --> I[SplitCommand]
  E --> J[Append canonical groups or prune owned handlers]
  J --> K[Updated settings map]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
  A[Claude settings map] --> B[MergeManagedHooks or RemoveManagedHooks]
  B --> C[managedHookPlan]
  C --> D[agenthooks.Plan]
  B --> E[agenthooks.Config]
  E --> F[HooksMap]
  E --> G[withoutOwnedHandlers]
  G --> H[CommandHandler predicates]
  H --> I[SplitCommand]
  E --> J[Append canonical groups or prune owned handlers]
  J --> K[Updated settings map]
Loading

Reviews (1): Last reviewed commit: "refactor: introduce typed agent hook pla..." | Re-trigger Greptile

Comment thread internal/claudemanaged/usersettings.go Outdated
Comment on lines +180 to +191
func isGuardHookHandler(handler agenthooks.CommandHandler) bool {
if len(handler.Args) > 0 {
return false
}
if inField {
fields = append(fields, builder.String())
return IsGuardHookCommand(handler.Command)
}

func isManagedHookHandler(handler agenthooks.CommandHandler) bool {
if len(handler.Args) > 0 {
return false
}
return fields, true
return IsManagedHookCommand(handler.Command)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Split args are skipped

When an existing Claude settings file stores a hook as command: "kontext" with args: ["hook", "pre-tool-use"] or the Guard equivalent, commandHandlerFromMap can parse that shape, but these predicates immediately return false for any non-empty args. That makes HasCommand miss a Guard conflict warning, and it makes merge/remove treat an existing managed hook as foreign. A reinstall can append a second canonical hook, and uninstall can leave the split-form hook behind. If the shared helper accepts args, the Claude predicates should match the equivalent command-plus-args forms instead of ignoring them.

@tumberger tumberger force-pushed the refactor/agent-hook-installer branch from 4fef034 to 23caa4d Compare June 24, 2026 14:26
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