diff --git a/core/config_loader.py b/core/config_loader.py index d31827a..b76f2c4 100644 --- a/core/config_loader.py +++ b/core/config_loader.py @@ -219,9 +219,14 @@ def load_rules(event: Optional[str] = None) -> List[Rule]: os.path.join('.claude', 'hookify.*.local.md'), # Project-level os.path.expanduser(os.path.join('~', '.claude', 'hookify.*.local.md')), # Global ] + seen = set() files = [] for pattern in patterns: - files.extend(glob.glob(pattern)) + for f in glob.glob(pattern): + resolved = os.path.realpath(f) + if resolved not in seen: + seen.add(resolved) + files.append(f) for file_path in files: try: diff --git a/core/rule_engine.py b/core/rule_engine.py index f52ce26..309f83d 100644 --- a/core/rule_engine.py +++ b/core/rule_engine.py @@ -227,8 +227,8 @@ def _extract_field(self, field: str, tool_name: str, print(f"Warning: Encoding error in transcript {transcript_path}: {e}", file=sys.stderr) return '' elif field == 'user_prompt': - # For UserPromptSubmit events - return input_data.get('user_prompt', '') + # For UserPromptSubmit events — Claude Code sends 'prompt', not 'user_prompt' + return input_data.get('user_prompt') or input_data.get('prompt', '') # Handle special cases by tool type if tool_name == 'Bash':