mirror of
https://github.com/anthropics/claude-code.git
synced 2026-02-19 04:27:33 -08:00
Compare commits
3 Commits
v2.0.73
...
claude/sla
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
449aa9d3b0 | ||
|
|
5c92b97cc4 | ||
|
|
d213a74fc8 |
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## 2.0.74
|
||||
|
||||
- Added LSP (Language Server Protocol) tool for code intelligence features like go-to-definition, find references, and hover documentation
|
||||
- Added `/terminal-setup` support for Kitty, Alacritty, Zed, and Warp terminals
|
||||
- Added ctrl+t shortcut in `/theme` to toggle syntax highlighting on/off
|
||||
- Added syntax highlighting info to theme picker
|
||||
- Added guidance for macOS users when Alt shortcuts fail due to terminal configuration
|
||||
- Fixed skill `allowed-tools` not being applied to tools invoked by the skill
|
||||
- Fixed Opus 4.5 tip incorrectly showing when user was already using Opus
|
||||
- Fixed a potential crash when syntax highlighting isn't initialized correctly
|
||||
- Fixed visual bug in `/plugins discover` where list selection indicator showed while search box was focused
|
||||
- Fixed macOS keyboard shortcuts to display 'opt' instead of 'alt'
|
||||
- Improved `/context` command visualization with grouped skills and agents by source, slash commands, and sorted token count
|
||||
- [Windows] Fixed issue with improper rendering
|
||||
- [VSCode] Added gift tag pictogram for year-end promotion message
|
||||
|
||||
## 2.0.73
|
||||
|
||||
- Added clickable `[Image #N]` links that open attached images in the default viewer
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Rule evaluation engine for hookify plugin."""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from functools import lru_cache
|
||||
@@ -9,6 +10,13 @@ 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)
|
||||
@@ -24,6 +32,58 @@ 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."""
|
||||
|
||||
@@ -205,24 +265,10 @@ class RuleEngine:
|
||||
if field == 'reason':
|
||||
return input_data.get('reason', '')
|
||||
elif field == 'transcript':
|
||||
# Read transcript file if path provided
|
||||
# Read transcript file with size limits to prevent OOM
|
||||
transcript_path = input_data.get('transcript_path')
|
||||
if 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 ''
|
||||
return read_transcript_safely(transcript_path)
|
||||
elif field == 'user_prompt':
|
||||
# For UserPromptSubmit events
|
||||
return input_data.get('user_prompt', '')
|
||||
|
||||
@@ -1,26 +1,18 @@
|
||||
---
|
||||
description: "Cancel active Ralph Wiggum loop"
|
||||
allowed-tools: ["Bash"]
|
||||
allowed-tools: ["Bash(test -f .claude/ralph-loop.local.md:*)", "Bash(rm .claude/ralph-loop.local.md)", "Read(.claude/ralph-loop.local.md)"]
|
||||
hide-from-slash-command-tool: "true"
|
||||
---
|
||||
|
||||
# Cancel Ralph
|
||||
|
||||
```!
|
||||
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
|
||||
```
|
||||
To cancel the Ralph loop:
|
||||
|
||||
Check the output above:
|
||||
1. Check if `.claude/ralph-loop.local.md` exists using Bash: `test -f .claude/ralph-loop.local.md && echo "EXISTS" || echo "NOT_FOUND"`
|
||||
|
||||
1. **If FOUND_LOOP=false**:
|
||||
- Say "No active Ralph loop found."
|
||||
2. **If NOT_FOUND**: Say "No active Ralph loop found."
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
@@ -11,36 +11,6 @@ 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.
|
||||
|
||||
@@ -174,3 +174,30 @@ 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
|
||||
|
||||
Reference in New Issue
Block a user