Skip to content

[AUTOMATION] fix: optimize guard hook entry scan#238

Open
michiosw wants to merge 1 commit into
mainfrom
fix/optimize-guard-hook-entry-scan-daily
Open

[AUTOMATION] fix: optimize guard hook entry scan#238
michiosw wants to merge 1 commit into
mainfrom
fix/optimize-guard-hook-entry-scan-daily

Conversation

@michiosw
Copy link
Copy Markdown
Contributor

Summary
This optimizes Guard hook entry scans by walking nested hook commands in place and stopping at the first guard match.

Before this, hook status and uninstall fallback paths could format an entire hook entry with fmt.Sprintf and then scan the full string for a match, which did extra allocation and extra text scanning in internal/guard/cli/cli.go.

Now the canonical path walks the real command fields directly and can return as soon as a guard hook is found.

Why
This gives kontext-cli a cheaper maintenance/runtime path for Claude hook inspection:

Claude settings entry
-> walkHookCommands
-> guard hook classification without whole-entry string formatting

This PR does not broaden behavior beyond the optimization scope.

What changed
Optimized guard hook entry detection in internal/guard/cli/cli.go
Removed whole-entry fmt.Sprintf scanning for nested hook detection
Preserved hosted vs Guard hook classification and uninstall behavior
Updated no tests; existing guard CLI tests cover the touched paths

Verification
go test ./internal/guard/cli
go test ./internal/guard/judge -run 'TestStartLlamaServerHealthCheckAndStop|TestStartLlamaServerEarlyExitDoesNotWaitForStopTimeout' -count=1
go test ./...
go vet ./...
git diff --check

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 31, 2026

Greptile Summary

This PR optimizes Guard hook detection in Claude settings. The main changes are:

  • Replaces hook command visiting with a walker that can stop early.
  • Scans nested hook command fields directly instead of formatting whole entries.
  • Reuses the walker for Guard hook entry classification during cleanup.

Confidence Score: 4/5

This is close, but the cleanup fallback should be fixed before merging.

  • Normal nested Claude hook scanning appears preserved.

  • Flat command-shaped Guard entries can now survive uninstall and install cleanup.

  • The issue is contained to Guard hook entry classification.

  • internal/guard/cli/cli.go should preserve top-level command detection in isGuardHookEntry.

Important Files Changed

Filename Overview
internal/guard/cli/cli.go Optimizes Guard hook scanning, but the new entry classifier misses flat command entries used by cleanup fallback paths.

Reviews (1): Last reviewed commit: "fix: optimize guard hook entry scan" | Re-trigger Greptile

Comment thread internal/guard/cli/cli.go
Comment on lines 540 to 547
func isGuardHookEntry(entry any) bool {
return isGuardHookCommand(fmt.Sprintf("%v", entry))
if command, ok := entry.(string); ok {
return isGuardHookCommand(command)
}
return walkHookCommands([]any{entry}, func(command string) bool {
return isGuardHookCommand(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.

P1 Keep flat hook removal This fallback is used when an entry is not a normal matcher group or does not have a nested hooks array. Before this change, a flat entry like {"type":"command","command":"/usr/local/bin/kontext hook --agent claude --mode observe"} was removed because the formatted entry contained the guard command. Now the map is wrapped and passed to walkHookCommands, which only checks nested group["hooks"], so uninstall can leave that Guard hook behind and install can append a duplicate canonical hook.

Suggested change
func isGuardHookEntry(entry any) bool {
return isGuardHookCommand(fmt.Sprintf("%v", entry))
if command, ok := entry.(string); ok {
return isGuardHookCommand(command)
}
return walkHookCommands([]any{entry}, func(command string) bool {
return isGuardHookCommand(command)
})
}
func isGuardHookEntry(entry any) bool {
if command, ok := entry.(string); ok {
return isGuardHookCommand(command)
}
if isGuardHookObject(entry) {
return true
}
return walkHookCommands([]any{entry}, func(command string) bool {
return isGuardHookCommand(command)
})
}

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