diff --git a/CLAUDE.md b/CLAUDE.md index 3d9f720..d80ad4f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,6 +1,46 @@ # CLAUDE.md This file provides guidance to Claude Code when working with code in this repository. +## ⛔ MANDATORY BEHAVIOR RULES - READ FIRST + +**These rules are NON-NEGOTIABLE. Violating them wastes the user's time and money.** + +### 1. WHEN USER ASKS YOU TO CHECK SOMETHING - CHECK EVERYTHING +- Search ALL locations, not just where you think it is +- Check cache directories: `~/.claude/plugins/cache/` +- Check installed: `~/.claude/plugins/marketplaces/` +- Check source: `~/claude-plugins-work/` +- **NEVER say "no" or "that's not the issue" without exhaustive verification** + +### 2. WHEN USER SAYS SOMETHING IS WRONG - BELIEVE THEM +- The user knows their system better than you +- Investigate thoroughly before disagreeing +- If user suspects cache, CHECK THE CACHE +- If user suspects a file, READ THE FILE +- **Your confidence is often wrong. User's instincts are often right.** + +### 3. NEVER SAY "DONE" WITHOUT VERIFICATION +- Run the actual command/script to verify +- Show the output to the user +- Check ALL affected locations +- **"Done" means VERIFIED WORKING, not "I made changes"** + +### 4. SHOW EXACTLY WHAT USER ASKS FOR +- If user asks for messages, show the MESSAGES +- If user asks for code, show the CODE +- If user asks for output, show the OUTPUT +- **Don't interpret or summarize unless asked** + +### 5. AFTER PLUGIN UPDATES - ALWAYS CLEAR CACHE +```bash +rm -rf ~/.claude/plugins/cache/leo-claude-mktplace/ +./scripts/verify-hooks.sh +``` + +**FAILURE TO FOLLOW THESE RULES = WASTED USER TIME = UNACCEPTABLE** + +--- + ## Project Overview diff --git a/mcp-servers/gitea/mcp_server/tools/labels.py b/mcp-servers/gitea/mcp_server/tools/labels.py index 3fb87a7..719519f 100644 --- a/mcp-servers/gitea/mcp_server/tools/labels.py +++ b/mcp-servers/gitea/mcp_server/tools/labels.py @@ -275,6 +275,7 @@ class LabelTools: ) -> Dict: """ Create a label at the appropriate level (org or repo) based on category. + Skips if label already exists (checks both org and repo levels). Organization labels: Agent, Complexity, Effort, Priority, Risk, Source, Type Repository labels: Component, Tech @@ -286,7 +287,7 @@ class LabelTools: repo: Repository in 'owner/repo' format Returns: - Created label dictionary with 'level' key indicating where it was created + Created label dictionary with 'level' key, or 'skipped' if already exists """ loop = asyncio.get_event_loop() @@ -294,6 +295,41 @@ class LabelTools: if not target_repo or '/' not in target_repo: raise ValueError("Use 'owner/repo' format (e.g. 'org/repo-name')") + owner = target_repo.split('/')[0] + is_org = await loop.run_in_executor( + None, + lambda: self.gitea.is_org_repo(target_repo) + ) + + # Fetch existing labels to check for duplicates + existing_labels = await self.get_labels(target_repo) + all_existing = existing_labels.get('organization', []) + existing_labels.get('repository', []) + existing_names = [label['name'].lower() for label in all_existing] + + # Normalize the new label name for comparison + name_normalized = name.lower() + + # Also check for format variations (Type/Bug vs Type: Bug) + name_variations = [name_normalized] + if '/' in name: + name_variations.append(name.replace('/', ': ').lower()) + name_variations.append(name.replace('/', ':').lower()) + elif ': ' in name: + name_variations.append(name.replace(': ', '/').lower()) + elif ':' in name: + name_variations.append(name.replace(':', '/').lower()) + + # Check if label already exists in any format + for variation in name_variations: + if variation in existing_names: + logger.info(f"Label '{name}' already exists (found as '{variation}'), skipping") + return { + 'name': name, + 'skipped': True, + 'reason': f"Label already exists", + 'level': 'existing' + } + # Parse category from label name category = None if '/' in name: @@ -301,13 +337,6 @@ class LabelTools: elif ':' in name: category = name.split(':')[0].strip().lower().rstrip('s') - # Determine level - owner = target_repo.split('/')[0] - is_org = await loop.run_in_executor( - None, - lambda: self.gitea.is_org_repo(target_repo) - ) - # If it's an org repo and the category is an org-level category, create at org level if is_org and category in self.ORG_LABEL_CATEGORIES: result = await loop.run_in_executor( @@ -315,6 +344,7 @@ class LabelTools: lambda: self.gitea.create_org_label(owner, name, color, description) ) result['level'] = 'organization' + result['skipped'] = False logger.info(f"Created organization label '{name}' in {owner}") else: # Create at repo level @@ -323,6 +353,7 @@ class LabelTools: lambda: self.gitea.create_label(name, color, description, target_repo) ) result['level'] = 'repository' + result['skipped'] = False logger.info(f"Created repository label '{name}' in {target_repo}") return result diff --git a/plugins/claude-config-maintainer/hooks/enforce-rules.sh b/plugins/claude-config-maintainer/hooks/enforce-rules.sh new file mode 100755 index 0000000..a451a1a --- /dev/null +++ b/plugins/claude-config-maintainer/hooks/enforce-rules.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# claude-config-maintainer: enforce mandatory behavior rules +# Checks if CLAUDE.md has the rules, adds them if missing + +PREFIX="[claude-config-maintainer]" + +# Find CLAUDE.md in current directory or parent +CLAUDE_MD="" +if [ -f "./CLAUDE.md" ]; then + CLAUDE_MD="./CLAUDE.md" +elif [ -f "../CLAUDE.md" ]; then + CLAUDE_MD="../CLAUDE.md" +fi + +# If no CLAUDE.md found, exit silently +if [ -z "$CLAUDE_MD" ]; then + exit 0 +fi + +# Check if mandatory rules exist +if grep -q "MANDATORY BEHAVIOR RULES" "$CLAUDE_MD" 2>/dev/null; then + # Rules exist, all good + exit 0 +fi + +# Rules missing - add them +RULES='## ⛔ MANDATORY BEHAVIOR RULES - READ FIRST + +**These rules are NON-NEGOTIABLE. Violating them wastes the user'\''s time and money.** + +### 1. WHEN USER ASKS YOU TO CHECK SOMETHING - CHECK EVERYTHING +- Search ALL locations, not just where you think it is +- Check cache directories: `~/.claude/plugins/cache/` +- Check installed: `~/.claude/plugins/marketplaces/` +- Check source directories +- **NEVER say "no" or "that'\''s not the issue" without exhaustive verification** + +### 2. WHEN USER SAYS SOMETHING IS WRONG - BELIEVE THEM +- The user knows their system better than you +- Investigate thoroughly before disagreeing +- **Your confidence is often wrong. User'\''s instincts are often right.** + +### 3. NEVER SAY "DONE" WITHOUT VERIFICATION +- Run the actual command/script to verify +- Show the output to the user +- **"Done" means VERIFIED WORKING, not "I made changes"** + +### 4. SHOW EXACTLY WHAT USER ASKS FOR +- If user asks for messages, show the MESSAGES +- If user asks for code, show the CODE +- **Do not interpret or summarize unless asked** + +**FAILURE TO FOLLOW THESE RULES = WASTED USER TIME = UNACCEPTABLE** + +--- + +' + +# Create temp file with rules + existing content +{ + head -1 "$CLAUDE_MD" + echo "" + echo "$RULES" + tail -n +2 "$CLAUDE_MD" +} > "${CLAUDE_MD}.tmp" + +mv "${CLAUDE_MD}.tmp" "$CLAUDE_MD" +echo "$PREFIX Added mandatory behavior rules to CLAUDE.md" diff --git a/plugins/claude-config-maintainer/hooks/hooks.json b/plugins/claude-config-maintainer/hooks/hooks.json new file mode 100644 index 0000000..d80c531 --- /dev/null +++ b/plugins/claude-config-maintainer/hooks/hooks.json @@ -0,0 +1,10 @@ +{ + "hooks": { + "SessionStart": [ + { + "type": "command", + "command": "${CLAUDE_PLUGIN_ROOT}/hooks/enforce-rules.sh" + } + ] + } +} diff --git a/scripts/post-update.sh b/scripts/post-update.sh index e8e9041..b93d8fc 100755 --- a/scripts/post-update.sh +++ b/scripts/post-update.sh @@ -78,3 +78,8 @@ main() { } main "$@" + +# Clear plugin cache to ensure fresh hooks are loaded +echo "Clearing plugin cache..." +rm -rf ~/.claude/plugins/cache/leo-claude-mktplace/ +echo "Cache cleared" diff --git a/scripts/verify-hooks.sh b/scripts/verify-hooks.sh new file mode 100755 index 0000000..bb6fff8 --- /dev/null +++ b/scripts/verify-hooks.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Verify all hooks are command type (not prompt) +# Run this after any plugin update + +echo "=== HOOK VERIFICATION ===" +echo "" + +FAILED=0 + +# Check ALL hooks.json files in .claude directory +for f in $(find ~/.claude -name "hooks.json" 2>/dev/null); do + if grep -q '"type": "prompt"' "$f" || grep -q '"type":"prompt"' "$f"; then + echo "❌ PROMPT HOOK FOUND: $f" + FAILED=1 + fi +done + +# Check cache specifically +if [ -d ~/.claude/plugins/cache/leo-claude-mktplace ]; then + echo "❌ CACHE EXISTS: ~/.claude/plugins/cache/leo-claude-mktplace" + echo " Run: rm -rf ~/.claude/plugins/cache/leo-claude-mktplace/" + FAILED=1 +fi + +# Verify installed hooks are command type +for plugin in doc-guardian code-sentinel projman pr-review project-hygiene; do + HOOK_FILE=~/.claude/plugins/marketplaces/leo-claude-mktplace/plugins/$plugin/hooks/hooks.json + if [ -f "$HOOK_FILE" ]; then + if grep -q '"type": "command"' "$HOOK_FILE" || grep -q '"type":"command"' "$HOOK_FILE"; then + echo "✓ $plugin: command type" + else + echo "❌ $plugin: NOT command type" + FAILED=1 + fi + fi +done + +echo "" +if [ $FAILED -eq 0 ]; then + echo "✓ All hooks verified OK" +else + echo "❌ ISSUES FOUND - fix before using" + exit 1 +fi