Compare commits

..

1 Commits

Author SHA1 Message Date
Claude
4dfcfddbae docs: Clarify Skills feature vs slash commands in changelog
Update the 2.0.20 changelog entry to explain that:
- Skills is a new feature for specialized capabilities
- The Skill tool also handles slash command invocation
- This is an internal change, not a replacement of slash commands
- Slash commands continue to work the same way for users

This addresses confusion where people thought slash commands were
being replaced with skills.
2025-12-20 18:59:55 +00:00
5 changed files with 63 additions and 98 deletions

View File

@@ -370,7 +370,7 @@
## 2.0.20
- Added support for Claude Skills
- Added support for Claude Skills. Skills are a new feature that provide specialized capabilities and domain knowledge to Claude. The internal "Skill" tool also handles slash command invocation (previously done by the "SlashCommand" tool) - this is an internal change to how Claude invokes your slash commands, not a replacement of slash commands. Slash commands continue to work exactly the same way for users.
## 2.0.19

View File

@@ -1,7 +1,6 @@
#!/usr/bin/env python3
"""Rule evaluation engine for hookify plugin."""
import os
import re
import sys
from functools import lru_cache
@@ -10,13 +9,6 @@ from typing import List, Dict, Any, Optional
# Import from local module
from hookify.core.config_loader import Rule, Condition
# Maximum transcript size to load into memory (10MB default)
# For larger files, only the tail is read to prevent OOM
MAX_TRANSCRIPT_SIZE_BYTES = 10 * 1024 * 1024 # 10MB
# Size threshold for warning about large transcripts
TRANSCRIPT_WARNING_SIZE_BYTES = 5 * 1024 * 1024 # 5MB
# Cache compiled regexes (max 128 patterns)
@lru_cache(maxsize=128)
@@ -32,58 +24,6 @@ def compile_regex(pattern: str) -> re.Pattern:
return re.compile(pattern, re.IGNORECASE)
def read_transcript_safely(transcript_path: str) -> str:
"""Read transcript file with size limits to prevent OOM.
For large transcripts (>10MB), only reads the tail of the file
to prevent memory exhaustion. This preserves the most recent
conversation context which is typically what rules care about.
Args:
transcript_path: Path to the transcript file
Returns:
Transcript content as string, possibly truncated for large files
"""
try:
file_size = os.path.getsize(transcript_path)
# Warn about large transcripts
if file_size > TRANSCRIPT_WARNING_SIZE_BYTES:
size_mb = file_size / (1024 * 1024)
print(f"Warning: Large transcript ({size_mb:.1f}MB): {transcript_path}", file=sys.stderr)
# For files within limit, read normally
if file_size <= MAX_TRANSCRIPT_SIZE_BYTES:
with open(transcript_path, 'r') as f:
return f.read()
# For large files, read only the tail to prevent OOM
size_mb = file_size / (1024 * 1024)
limit_mb = MAX_TRANSCRIPT_SIZE_BYTES / (1024 * 1024)
print(f"Warning: Transcript too large ({size_mb:.1f}MB), reading last {limit_mb:.0f}MB only", file=sys.stderr)
with open(transcript_path, 'r') as f:
# Seek to position near end, leaving room for MAX_TRANSCRIPT_SIZE_BYTES
f.seek(file_size - MAX_TRANSCRIPT_SIZE_BYTES)
# Skip partial line at seek position
f.readline()
return f.read()
except FileNotFoundError:
print(f"Warning: Transcript file not found: {transcript_path}", file=sys.stderr)
return ''
except PermissionError:
print(f"Warning: Permission denied reading transcript: {transcript_path}", file=sys.stderr)
return ''
except (IOError, OSError) as e:
print(f"Warning: Error reading transcript {transcript_path}: {e}", file=sys.stderr)
return ''
except UnicodeDecodeError as e:
print(f"Warning: Encoding error in transcript {transcript_path}: {e}", file=sys.stderr)
return ''
class RuleEngine:
"""Evaluates rules against hook input data."""
@@ -265,10 +205,24 @@ class RuleEngine:
if field == 'reason':
return input_data.get('reason', '')
elif field == 'transcript':
# Read transcript file with size limits to prevent OOM
# Read transcript file if path provided
transcript_path = input_data.get('transcript_path')
if transcript_path:
return read_transcript_safely(transcript_path)
try:
with open(transcript_path, 'r') as f:
return f.read()
except FileNotFoundError:
print(f"Warning: Transcript file not found: {transcript_path}", file=sys.stderr)
return ''
except PermissionError:
print(f"Warning: Permission denied reading transcript: {transcript_path}", file=sys.stderr)
return ''
except (IOError, OSError) as e:
print(f"Warning: Error reading transcript {transcript_path}: {e}", file=sys.stderr)
return ''
except UnicodeDecodeError as e:
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', '')

View File

@@ -1,18 +1,26 @@
---
description: "Cancel active Ralph Wiggum loop"
allowed-tools: ["Bash(test -f .claude/ralph-loop.local.md:*)", "Bash(rm .claude/ralph-loop.local.md)", "Read(.claude/ralph-loop.local.md)"]
allowed-tools: ["Bash"]
hide-from-slash-command-tool: "true"
---
# Cancel Ralph
To cancel the Ralph loop:
```!
if [[ -f .claude/ralph-loop.local.md ]]; then
ITERATION=$(grep '^iteration:' .claude/ralph-loop.local.md | sed 's/iteration: *//')
echo "FOUND_LOOP=true"
echo "ITERATION=$ITERATION"
else
echo "FOUND_LOOP=false"
fi
```
1. Check if `.claude/ralph-loop.local.md` exists using Bash: `test -f .claude/ralph-loop.local.md && echo "EXISTS" || echo "NOT_FOUND"`
Check the output above:
2. **If NOT_FOUND**: Say "No active Ralph loop found."
1. **If FOUND_LOOP=false**:
- Say "No active Ralph loop found."
3. **If EXISTS**:
- Read `.claude/ralph-loop.local.md` to get the current iteration number from the `iteration:` field
- Remove the file using Bash: `rm .claude/ralph-loop.local.md`
- Report: "Cancelled Ralph loop (was at iteration N)" where N is the iteration value
2. **If FOUND_LOOP=true**:
- Use Bash: `rm .claude/ralph-loop.local.md`
- Report: "Cancelled Ralph loop (was at iteration N)" where N is the ITERATION value from above.

View File

@@ -11,6 +11,36 @@ Execute the setup script to initialize the Ralph loop:
```!
"${CLAUDE_PLUGIN_ROOT}/scripts/setup-ralph-loop.sh" $ARGUMENTS
# Extract and display completion promise if set
if [ -f .claude/ralph-loop.local.md ]; then
PROMISE=$(grep '^completion_promise:' .claude/ralph-loop.local.md | sed 's/completion_promise: *//' | sed 's/^"\(.*\)"$/\1/')
if [ -n "$PROMISE" ] && [ "$PROMISE" != "null" ]; then
echo ""
echo "═══════════════════════════════════════════════════════════"
echo "CRITICAL - Ralph Loop Completion Promise"
echo "═══════════════════════════════════════════════════════════"
echo ""
echo "To complete this loop, output this EXACT text:"
echo " <promise>$PROMISE</promise>"
echo ""
echo "STRICT REQUIREMENTS (DO NOT VIOLATE):"
echo " ✓ Use <promise> XML tags EXACTLY as shown above"
echo " ✓ The statement MUST be completely and unequivocally TRUE"
echo " ✓ Do NOT output false statements to exit the loop"
echo " ✓ Do NOT lie even if you think you should exit"
echo ""
echo "IMPORTANT - Do not circumvent the loop:"
echo " Even if you believe you're stuck, the task is impossible,"
echo " or you've been running too long - you MUST NOT output a"
echo " false promise statement. The loop is designed to continue"
echo " until the promise is GENUINELY TRUE. Trust the process."
echo ""
echo " If the loop should stop, the promise statement will become"
echo " true naturally. Do not force it by lying."
echo "═══════════════════════════════════════════════════════════"
fi
fi
```
Please work on the task. When you try to exit, the Ralph loop will feed the SAME PROMPT back to you for the next iteration. You'll see your previous work in files and git history, allowing you to iterate and improve.

View File

@@ -174,30 +174,3 @@ if [[ -n "$PROMPT" ]]; then
echo ""
echo "$PROMPT"
fi
# Display completion promise requirements if set
if [[ "$COMPLETION_PROMISE" != "null" ]]; then
echo ""
echo "═══════════════════════════════════════════════════════════"
echo "CRITICAL - Ralph Loop Completion Promise"
echo "═══════════════════════════════════════════════════════════"
echo ""
echo "To complete this loop, output this EXACT text:"
echo " <promise>$COMPLETION_PROMISE</promise>"
echo ""
echo "STRICT REQUIREMENTS (DO NOT VIOLATE):"
echo " ✓ Use <promise> XML tags EXACTLY as shown above"
echo " ✓ The statement MUST be completely and unequivocally TRUE"
echo " ✓ Do NOT output false statements to exit the loop"
echo " ✓ Do NOT lie even if you think you should exit"
echo ""
echo "IMPORTANT - Do not circumvent the loop:"
echo " Even if you believe you're stuck, the task is impossible,"
echo " or you've been running too long - you MUST NOT output a"
echo " false promise statement. The loop is designed to continue"
echo " until the promise is GENUINELY TRUE. Trust the process."
echo ""
echo " If the loop should stop, the promise statement will become"
echo " true naturally. Do not force it by lying."
echo "═══════════════════════════════════════════════════════════"
fi