mirror of
https://github.com/anthropics/claude-code.git
synced 2026-02-19 04:27:33 -08:00
Compare commits
1 Commits
bac22cb316
...
claude/sla
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69585d4ffa |
@@ -25,6 +25,7 @@ Learn more in the [official plugins documentation](https://docs.claude.com/en/do
|
|||||||
| [pr-review-toolkit](./pr-review-toolkit/) | Comprehensive PR review agents specializing in comments, tests, error handling, type design, code quality, and code simplification | **Command:** `/pr-review-toolkit:review-pr` - Run with optional review aspects (comments, tests, errors, types, code, simplify, all)<br>**Agents:** `comment-analyzer`, `pr-test-analyzer`, `silent-failure-hunter`, `type-design-analyzer`, `code-reviewer`, `code-simplifier` |
|
| [pr-review-toolkit](./pr-review-toolkit/) | Comprehensive PR review agents specializing in comments, tests, error handling, type design, code quality, and code simplification | **Command:** `/pr-review-toolkit:review-pr` - Run with optional review aspects (comments, tests, errors, types, code, simplify, all)<br>**Agents:** `comment-analyzer`, `pr-test-analyzer`, `silent-failure-hunter`, `type-design-analyzer`, `code-reviewer`, `code-simplifier` |
|
||||||
| [ralph-wiggum](./ralph-wiggum/) | Interactive self-referential AI loops for iterative development. Claude works on the same task repeatedly until completion | **Commands:** `/ralph-loop`, `/cancel-ralph` - Start/stop autonomous iteration loops<br>**Hook:** Stop - Intercepts exit attempts to continue iteration |
|
| [ralph-wiggum](./ralph-wiggum/) | Interactive self-referential AI loops for iterative development. Claude works on the same task repeatedly until completion | **Commands:** `/ralph-loop`, `/cancel-ralph` - Start/stop autonomous iteration loops<br>**Hook:** Stop - Intercepts exit attempts to continue iteration |
|
||||||
| [security-guidance](./security-guidance/) | Security reminder hook that warns about potential security issues when editing files | **Hook:** PreToolUse - Monitors 9 security patterns including command injection, XSS, eval usage, dangerous HTML, pickle deserialization, and os.system calls |
|
| [security-guidance](./security-guidance/) | Security reminder hook that warns about potential security issues when editing files | **Hook:** PreToolUse - Monitors 9 security patterns including command injection, XSS, eval usage, dangerous HTML, pickle deserialization, and os.system calls |
|
||||||
|
| [slack-quote-formatter](./slack-quote-formatter/) | Enhances visual display of Slack forwarded and quoted messages with distinctive Unicode box formatting | **Hook:** UserPromptSubmit - Transforms `[Forwarded Message]` blocks into visually distinctive formatted boxes with clear boundaries and indentation |
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|||||||
18
plugins/slack-quote-formatter/.claude-plugin/plugin.json
Normal file
18
plugins/slack-quote-formatter/.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "slack-quote-formatter",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Enhances visual display of Slack forwarded and quoted messages with distinctive formatting",
|
||||||
|
"author": {
|
||||||
|
"name": "Anthropic",
|
||||||
|
"email": "support@anthropic.com"
|
||||||
|
},
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"slack",
|
||||||
|
"formatting",
|
||||||
|
"quotes",
|
||||||
|
"messages",
|
||||||
|
"visual"
|
||||||
|
],
|
||||||
|
"hooks": "./hooks/hooks.json"
|
||||||
|
}
|
||||||
87
plugins/slack-quote-formatter/README.md
Normal file
87
plugins/slack-quote-formatter/README.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# Slack Quote Formatter
|
||||||
|
|
||||||
|
Enhances the visual display of Slack forwarded and quoted messages with distinctive Unicode box formatting.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
When Claude Code receives messages from Slack that include forwarded messages, they typically appear as plain text:
|
||||||
|
|
||||||
|
```
|
||||||
|
[Forwarded Message]
|
||||||
|
From: Felix Klock
|
||||||
|
Message: I assume it would be a matter of reviewing the entries...
|
||||||
|
```
|
||||||
|
|
||||||
|
This plugin transforms these plain blocks into visually distinctive formatted quotes:
|
||||||
|
|
||||||
|
```
|
||||||
|
╔════════════════════════════════════════════════════════════════════╗
|
||||||
|
║ FORWARDED MESSAGE ║
|
||||||
|
╠════════════════════════════════════════════════════════════════════╣
|
||||||
|
║ From: Felix Klock ║
|
||||||
|
╟────────────────────────────────────────────────────────────────────╢
|
||||||
|
║ I assume it would be a matter of reviewing the entries... ║
|
||||||
|
╚════════════════════════════════════════════════════════════════════╝
|
||||||
|
```
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Unicode box drawing characters for clear visual boundaries
|
||||||
|
- Distinct header section highlighting "FORWARDED MESSAGE"
|
||||||
|
- Sender information prominently displayed
|
||||||
|
- Message content indented for quote-like appearance
|
||||||
|
- Automatic text wrapping for long messages
|
||||||
|
- Handles multiple forwarded messages in a single prompt
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
This plugin is included in the Claude Code plugins repository. To enable it:
|
||||||
|
|
||||||
|
1. Add the plugin to your project's `.claude/settings.json`:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"plugins": [
|
||||||
|
"path/to/plugins/slack-quote-formatter"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Or install via the Claude Code plugin command:
|
||||||
|
```
|
||||||
|
/plugin add slack-quote-formatter
|
||||||
|
```
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
The plugin registers a `UserPromptSubmit` hook that:
|
||||||
|
|
||||||
|
1. Intercepts incoming prompts
|
||||||
|
2. Detects `[Forwarded Message]` blocks in the Slack context
|
||||||
|
3. Transforms them into formatted boxes with visual distinction
|
||||||
|
4. Passes the transformed prompt to Claude
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
No configuration required. The plugin automatically activates when Slack forwarded messages are detected.
|
||||||
|
|
||||||
|
## Plugin Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
slack-quote-formatter/
|
||||||
|
├── .claude-plugin/
|
||||||
|
│ └── plugin.json # Plugin metadata
|
||||||
|
├── hooks/
|
||||||
|
│ ├── hooks.json # Hook configuration
|
||||||
|
│ └── format_slack_quotes.py # Transformation logic
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why Visual Distinction Matters
|
||||||
|
|
||||||
|
When working with Slack context in Claude Code, quoted messages can easily blend into the surrounding text, making it harder to:
|
||||||
|
|
||||||
|
- Identify what content is quoted vs. original
|
||||||
|
- Understand the source of different pieces of information
|
||||||
|
- Parse complex threads with multiple forwarded messages
|
||||||
|
|
||||||
|
This plugin makes quoted content immediately recognizable, improving readability and reducing confusion.
|
||||||
185
plugins/slack-quote-formatter/hooks/format_slack_quotes.py
Executable file
185
plugins/slack-quote-formatter/hooks/format_slack_quotes.py
Executable file
@@ -0,0 +1,185 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Slack Quote Formatter - UserPromptSubmit Hook
|
||||||
|
|
||||||
|
Transforms plain Slack forwarded/quoted messages into visually distinctive
|
||||||
|
formatted blocks with Unicode box characters and better layout.
|
||||||
|
|
||||||
|
Before:
|
||||||
|
[Forwarded Message]
|
||||||
|
From: John Doe
|
||||||
|
Message: Here is some text...
|
||||||
|
|
||||||
|
After:
|
||||||
|
╔═══════════════════════════════════════════════════════════╗
|
||||||
|
║ FORWARDED MESSAGE ║
|
||||||
|
╠═══════════════════════════════════════════════════════════╣
|
||||||
|
║ From: John Doe ║
|
||||||
|
╟───────────────────────────────────────────────────────────╢
|
||||||
|
║ Here is some text... ║
|
||||||
|
╚═══════════════════════════════════════════════════════════╝
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def format_forwarded_message(from_line: str, message_content: str) -> str:
|
||||||
|
"""Format a single forwarded message with visual box styling."""
|
||||||
|
|
||||||
|
# Box drawing characters
|
||||||
|
TOP_LEFT = "╔"
|
||||||
|
TOP_RIGHT = "╗"
|
||||||
|
BOTTOM_LEFT = "╚"
|
||||||
|
BOTTOM_RIGHT = "╝"
|
||||||
|
HORIZONTAL = "═"
|
||||||
|
VERTICAL = "║"
|
||||||
|
LEFT_T = "╠"
|
||||||
|
RIGHT_T = "╣"
|
||||||
|
LEFT_LIGHT = "╟"
|
||||||
|
RIGHT_LIGHT = "╢"
|
||||||
|
LIGHT_HORIZONTAL = "─"
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
BOX_WIDTH = 70
|
||||||
|
INNER_WIDTH = BOX_WIDTH - 4 # Account for "║ " and " ║"
|
||||||
|
|
||||||
|
def pad_line(text: str, width: int = INNER_WIDTH) -> str:
|
||||||
|
"""Pad a line to fill the box width."""
|
||||||
|
if len(text) > width:
|
||||||
|
return text[:width]
|
||||||
|
return text + " " * (width - len(text))
|
||||||
|
|
||||||
|
def wrap_text(text: str, width: int) -> list:
|
||||||
|
"""Wrap text to fit within the specified width."""
|
||||||
|
words = text.split()
|
||||||
|
lines = []
|
||||||
|
current_line = []
|
||||||
|
current_length = 0
|
||||||
|
|
||||||
|
for word in words:
|
||||||
|
word_len = len(word)
|
||||||
|
if current_length + word_len + (1 if current_line else 0) <= width:
|
||||||
|
current_line.append(word)
|
||||||
|
current_length += word_len + (1 if len(current_line) > 1 else 0)
|
||||||
|
else:
|
||||||
|
if current_line:
|
||||||
|
lines.append(" ".join(current_line))
|
||||||
|
current_line = [word]
|
||||||
|
current_length = word_len
|
||||||
|
|
||||||
|
if current_line:
|
||||||
|
lines.append(" ".join(current_line))
|
||||||
|
|
||||||
|
return lines if lines else [""]
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
# Top border with header
|
||||||
|
lines.append(f"{TOP_LEFT}{HORIZONTAL * (BOX_WIDTH - 2)}{TOP_RIGHT}")
|
||||||
|
|
||||||
|
# Header line
|
||||||
|
header = "FORWARDED MESSAGE"
|
||||||
|
lines.append(f"{VERTICAL} {pad_line(header)}{VERTICAL}")
|
||||||
|
|
||||||
|
# Separator after header
|
||||||
|
lines.append(f"{LEFT_T}{HORIZONTAL * (BOX_WIDTH - 2)}{RIGHT_T}")
|
||||||
|
|
||||||
|
# From line
|
||||||
|
from_display = from_line.strip()
|
||||||
|
lines.append(f"{VERTICAL} {pad_line(from_display)}{VERTICAL}")
|
||||||
|
|
||||||
|
# Light separator before message
|
||||||
|
lines.append(f"{LEFT_LIGHT}{LIGHT_HORIZONTAL * (BOX_WIDTH - 2)}{RIGHT_LIGHT}")
|
||||||
|
|
||||||
|
# Message content (indented and wrapped)
|
||||||
|
message_lines = message_content.strip().split("\n")
|
||||||
|
for msg_line in message_lines:
|
||||||
|
# Handle each line, wrapping if necessary
|
||||||
|
wrapped = wrap_text(msg_line, INNER_WIDTH - 2) # Extra indent
|
||||||
|
for wrapped_line in wrapped:
|
||||||
|
indented = " " + wrapped_line # Add indent for quote appearance
|
||||||
|
lines.append(f"{VERTICAL} {pad_line(indented)}{VERTICAL}")
|
||||||
|
|
||||||
|
# Bottom border
|
||||||
|
lines.append(f"{BOTTOM_LEFT}{HORIZONTAL * (BOX_WIDTH - 2)}{BOTTOM_RIGHT}")
|
||||||
|
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def transform_slack_context(text: str) -> str:
|
||||||
|
"""
|
||||||
|
Find and transform [Forwarded Message] blocks in the text.
|
||||||
|
|
||||||
|
Matches patterns like:
|
||||||
|
[Forwarded Message]
|
||||||
|
From: Name Here
|
||||||
|
Message: Content here that may span
|
||||||
|
multiple lines until we hit the next section
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Pattern to match forwarded message blocks
|
||||||
|
# This handles the common format from Slack context
|
||||||
|
pattern = r'\[Forwarded Message\]\s*\n\s*From:\s*([^\n]+)\s*\nMessage:\s*(.+?)(?=\n\s*\[|\n\[pnkfelix\]|\n<|\Z)'
|
||||||
|
|
||||||
|
def replace_match(match):
|
||||||
|
from_name = match.group(1).strip()
|
||||||
|
message = match.group(2).strip()
|
||||||
|
|
||||||
|
formatted = format_forwarded_message(f"From: {from_name}", message)
|
||||||
|
return f"\n{formatted}\n"
|
||||||
|
|
||||||
|
# Apply transformation
|
||||||
|
result = re.sub(pattern, replace_match, text, flags=re.DOTALL)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point for the UserPromptSubmit hook."""
|
||||||
|
try:
|
||||||
|
# Read input from stdin
|
||||||
|
input_data = json.load(sys.stdin)
|
||||||
|
|
||||||
|
# Get the user prompt if available
|
||||||
|
user_prompt = input_data.get("user_prompt", "")
|
||||||
|
|
||||||
|
if not user_prompt:
|
||||||
|
# No prompt to transform, just pass through
|
||||||
|
print(json.dumps({}))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# Check if there are forwarded messages to format
|
||||||
|
if "[Forwarded Message]" not in user_prompt:
|
||||||
|
# Nothing to transform
|
||||||
|
print(json.dumps({}))
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
# Transform the prompt
|
||||||
|
transformed_prompt = transform_slack_context(user_prompt)
|
||||||
|
|
||||||
|
# If we made changes, return the transformed prompt
|
||||||
|
if transformed_prompt != user_prompt:
|
||||||
|
result = {
|
||||||
|
"transformedPrompt": transformed_prompt
|
||||||
|
}
|
||||||
|
print(json.dumps(result))
|
||||||
|
else:
|
||||||
|
print(json.dumps({}))
|
||||||
|
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
# No valid JSON input, pass through
|
||||||
|
print(json.dumps({}))
|
||||||
|
except Exception as e:
|
||||||
|
# Log error but don't block
|
||||||
|
error_output = {
|
||||||
|
"systemMessage": f"[slack-quote-formatter] Warning: {str(e)}"
|
||||||
|
}
|
||||||
|
print(json.dumps(error_output))
|
||||||
|
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
14
plugins/slack-quote-formatter/hooks/hooks.json
Normal file
14
plugins/slack-quote-formatter/hooks/hooks.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"UserPromptSubmit": [
|
||||||
|
{
|
||||||
|
"matcher": ".*",
|
||||||
|
"hooks": [
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/format_slack_quotes.py",
|
||||||
|
"timeout": 5000
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user